<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta woas_permanent="1" http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script woas_permanent="1" type="text/javascript">
/* <![CDATA[ */

/* DFQRCTsKlU-0000034-START */

var woas = {"version": "0.12.0"};

var __marker = "DFQRCTsKlU-0000034";

woas["config"] = {
"permit_edits":true,
"dblclick_edit":false,
"save_on_quit":false,
"nav_history":false,
"allow_diff":true,
"key_cache":true,
"cumulative_save":false,
"safe_mode":false,
"debug_mode":true,
"debug_closed":true,
"main_page":'Main Page',
"wsif_author":'Anonymous',
"wsif_ds":'',
"auto_save":0,
"new_tables_syntax":true,
"store_mts":true,
"folding_style":1,
"import_woas":240,
"import_wsif":240,
"auto_links":true,
"sort_tags":true,
"fixed_header":true,
"fixed_menu":true,
"menu_link":0};

var current = 'Main Page';

var backstack = [
];

var page_titles = [
'::Menu',
'Special::Advanced',
'Special::Import',
'Special::About',
'Main Page',
'Special::Search',
'Special::Lock',
'WoaS::Help::Security',
'Special::Options',
'WoaS::Help::Deprecated syntax',
'WoaS::Help::Special::Options',
'Special::Embed',
'WoaS::Plugins',
'WoaS History',
'Special::Export',
'Special::License',
'WoaS::Aliases',
'Special::ExportWSIF',
'WoaS::Help::WSIF',
'Special::ImportWSIF',
'WoaS::Help::Macros',
'WoaS::Help::Index',
'WoaS::Help::Syntax',
'WoaS::Help::Special::Advanced',
'WoaS::Help::Special::Erase Wiki',
'WoaS::Help::CSS',
'WoaS::Help::Special::Dead Pages',
'WoaS::Help::General usage',
'WoaS::Help::Nowiki text',
'WoaS::Template::Info',
'WoaS::Help::Wiki is read-only',
'WoaS::Help::Create a page',
'WoaS::Help::Delete a page',
'WoaS::Help::Editor',
'WoaS::Help::Edit a page',
'WoaS::Help::Erase all pages',
'WoaS::Help::Edit the menu',
'WoaS::Help::Headings',
'WoaS::Help::Rulers',
'WoaS::Help::Include wiki page',
'WoaS::Help::Javascript',
'WoaS::Help::Join lines of text',
'WoaS::Help::Namespaces',
'WoaS::Help::Text formatting',
'WoaS::Help::Rename a page',
'WoaS::Help::Page scrolling',
'WoaS::Help::Table of Contents',
'WoaS::Help::Tags',
'WoaS::Help::Publish wiki online',
'WoaS::Help::Run wiki on a web server',
'WoaS::Help::Requirements',
'WoaS::Help::Lists',
'WoaS::Help::Tables',
'WoaS::Help::Links',
'WoaS::Help::Images',
'WoaS::Help::Import',
'WoaS::Template::Search',
'WoaS::Help::Export',
'WoaS::Help::Template transclusion::Example',
'WoaS::Help::Template transclusion',
'WoaS::Help::Special::ExportWSIF',
'WoaS::Help::Special::ImportWSIF',
'WoaS::Hotkeys',
'WoaS::CSS::Core',
'WoaS::CSS::Custom',
'WoaS::CSS::Boot',
'WoaS::Help::Hotkeys',
'WoaS::Help::Plugins',
'WoaS::Help::Aliases',
'WoaS::ImportSettings',
'WoaS::Help::Include web page',
'WoaS::Help::Include text file',
'WoaS::Help::CSS::Core',
'WoaS::Help::CSS::Custom',
'WoaS::Help::Locked',
'WoaS::Help::CSS::Boot',
'WoaS::Help',
'WoaS::Help::Special::Orphaned Pages',
'WoaS::Help::Special::Recent Changes',
'WoaS::Help::Special::Search',
'WoaS::Help::Special::All Pages',
'WoaS::Help::Tagged',
'WoaS::Help::Unlocked',
'WoaS::Help::Untagged',
'WoaS::Help::Special::Export',
'WoaS::Help::Special::Import',
'WoaS::Help::Special::Backlinks',
'WoaS::Help::Menu',
'WoaS::Help::Duplicate a page',
'WoaS::Help::Go to a page',
'Improvements',
'log.txt',
'Examples',
'LMCP',
'AMASE Architecture',
'Development',
'Plugin::IconManager',
'Plugin::EventManager',
'Plugin::WindowService',
'SimpleExampleApp',
'timer',
'Scenario Files',
'Setup Tool',
'Running Amase',
'Contact Info',
'CMASI',
'Entities',
'Plugin Reference',
'Connecting to AMASE',
'More Examples',
'Plugin::EntityControl',
'AMASE Changes',
'AMASE C++ Plugins'
];

/* DFQRCTsKlU-0000034-DATA */
var page_attrs = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];

var page_mts = [1393361034,0,0,0,1392776125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1393349514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1385500126,1393595803,1385471656,1385740649,1385497177,1385497435,1385497457,1385566119,1385747256,1385741933,1385566050,1385574927,1385567502,1385745660,1385745161,1385996069,1385745088,1385995283,1410272309,1393525408,1393596364];

var pages = [
'\x3Cimg src=\'images/amaselogo_small.png\' /\x3E\n\
\n\
[[Main Page| Welcome to AMASE]]\n\
\n\
\n\
Using AMASE\n\
* [[Running Amase]]\n\
* [[LMCP|Overview of LMCP]]\n\
** [[CMASI]] Data Protocol\n\
** [[Entities]] Data Protocol\n\
* [[Connecting to AMASE]]\n\
* [[AMASE Changes]]\n\
\n\
\n\
AMASE Scenarios\n\
* [[Scenario Files]]\n\
* [[Setup Tool]]\n\
\n\
Developing AMASE\n\
* [[Development]]\n\
* [[SimpleExampleApp| A Simple Example]]\n\
* [[More Examples]]\n\
* [[AMASE Architecture]]\n\
* [[timer| AMASE Timer]]\n\
* [[AMASE C++ Plugins]]\n\
\n\
[[Plugin Reference]]\n\
\n\
\n\
[[Contact Info]]\n\
\n\
[[Include::WoaS::Template::Search]]\n\
\n\
WOAS STUFF\n\
\n\
[[::Menu| Menu]]\n\
\n\
[[Special::Options|Options]]\n\
\n\
* [[WoaS::Help]]\n\
* [[WoaS::Aliases]]\n\
* [[WoaS::Hotkeys]]\n\
* [[WoaS::Plugins]]\n\
\n\
* [[Special::All Pages|All Pages]]\n\
* [[Special::Go to|Go to...]]\n\
* [[Special::Recent Changes|Recent Changes]]\n\
\n\
* [[Special::Backlinks|Backlinks]]\n\
* [[Special::New Page|New Page]]\n\
* [[Special::Duplicate Page|Duplicate Page]]\n\
* [[Special::Delete Page|Delete Page]]\n\
\n\
* [[Special::Erase Wiki|Erase Wiki]]\n\
\n\
\n\
\n\
',
'== General\n\
* [[Special::Options]] - WoaS options\n\
* [[Special::Search]] - search all wiki pages\n\
== Lists\n\
* [[File::]], [[Image::]] - pages in the embedded namespaces\n\
* [[Locked::]], [[Unlocked::]] - encrypted/plain pages\n\
* [[Special::All Pages]] - user created pages\n\
* [[Special::Dead Pages]] - nonexistent pages that other pages link to\n\
* [[Special::Orphaned Pages]] - pages that no other page links to\n\
* [[Special::Recent Changes]] - recently modified pages\n\
* [[Tagged::]], [[Untagged::]] - tagged/untagged pages\n\
== Page commands\n\
* [[Special::Delete Page]] - delete a specific page\n\
* [[Special::Duplicate Page]] - duplicate a specific page\n\
* [[Special::Go to]] - go to a specific page\n\
* [[Special::New Page]] - create a new page\n\
== Special features\n\
* [[WoaS::Aliases]] - view/edit page title aliases\n\
* [[WoaS::CSS::Core]], [[WoaS::CSS::Custom]] - view the core CSS and edit the custom CSS\n\
* [[WoaS::Hotkeys]] - view/edit WoaS access keys and default key bindings\n\
* [[WoaS::Plugins]] - enable/disable and view/edit WoaS Javascript plugins\n\
== Wiki maintenance\n\
* [[Special::Import]] - import wiki from a WoaS html file (including earlier versions)\n\
* [[Special::ImportWSIF]] - import a [[WoaS::Help::WSIF|WSIF]] file containing one or more wiki pages\n\
* [[Special::Export]] - export wiki into multiple linked static XHTML files\n\
* [[Special::ExportWSIF]] - export wiki into multiple or single [[WoaS::Help::WSIF|WSIF]] files\n\
* [[Special::Erase Wiki]] - delete ALL wiki pages and reset with default data\n\
',
'\x3Cdiv\x3E\x3Cinput id="btn_import" class="woas_button_top" type="button" value="Import" onclick="import_wiki()" /\x3E\x3C/div\x3E\n\
=Import a wiki from a WoaS /HTML/ file\n\
/The imported WoaS file can be from a current or earlier version./\n\
\x3Cfieldset id="S2213" class="woas_input_wrap"\x3E\x3Clegend\x3ESource\x3C/legend\x3E\\\n\
\x3Clabel class="woas_input_wrap_left"\x3EFile: \x3Cinput class="woas_input_wrap_inline" id="filename_" type="file" /\x3E\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_import_config" onclick="woas.importer.i_config=this.checked"\x3EImport configuration (except WSIF datasource settings)\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_import_content" onclick="woas.ui._import_load_change()"\x3EImport content\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_import_styles" onclick="woas.ui._import_load_change()"\x3EImport custom CSS\x3C/label\x3E\n\
\x3C/fieldset\x3E\\\n\
[[Include::WoaS::ImportSettings]]\\\n\
\x3Cscript type="text/javascript"\x3E\n\
woas.ui._import_load(false);\n\
\x3C/script\x3E\n\
',
'[[Special::TOC]]\n\
= Welcome to Wiki on a Stick!\n\
Wiki on a Stick (*WoaS*) is a [[http://en.wikipedia.org/wiki/Wiki|wiki]] that lives in *one self-modifying XHTML file*. It\'s perfect for use at home or office, on your laptop or USB pen drive. It can be used as a personal notepad, calendar, repository for software documentation, and for many other purposes; it allows full customization and extension by your own scripts and plugins. It also offers [[WoaS::Help::Security|AES encryption]] of pages.\n\
== Version\n\
This version of WoaS is based on v0.12.0 but has been modified by Paul Levey ([[http://pvhl.users.sourceforge.net/|pvhl]]) to fix various bugs present in the official 0.12.0 release. It is expected that these changes will some day make their way into the official code. The latest version of this file (woas-fix.html) can be found on [[http://stickwiki.svn.sourceforge.net/viewvc/stickwiki/branches/pvhl/|my WoaS SVN branch]]. It is a simple matter to import any content you have in other WoaS files using the [[Special::Import|import page]]. My thanks to [[http://bookonastick.wordpress.com/|Little Girl]] for her work on the Help pages and help with testing.\n\
\n\
Versions 0.9&tilde;0.12.0 by Daniele C. ([[http://sf.net/users/legolas558/|legolas558]])\n\
Original version (v0.01 &tilde; v0.04) by Andr\u00e9 Wagner\n\
\n\
\x3Cbig\x3E[[Special::License|Wiki on a Stick is licensed under the GNU/GPL license]].\x3C/big\x3E\n\
== Official Website\n\
\x3Cimg style="display: inline" id="img_logo" alt="WoaS Logo" src="%2FAAAAAXNSR0IArs4c6QAAAAJiS0dEAP%2BHj8y%2FAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2gEcDzUY4t9JowAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAI7SURBVEjHtdVPSFRRFAbw33ujljETWhaGo9YiCGoVuHDTIggE2xRBbgeEoFWQFARBq3ZCELQKgqJtbWtTEAitgqBNCZJFGGb%2B18Hxz20xr3HSmXEU%2Bt7ivnvf%2B757z3feOydSAZNh2QrW0IAm%2Bx2LVMS25e9h0UbFF5u1aI1qCvwMs9ZVRyStK6oq8D3M2xn7HdYSVRAYC3n1ocHRslDi4vCtbjprpspmcTH2BbtBwddQJjATZu0Wi36FvwFZqOk861atbUttvDku1SAHeUsKFb6MueQM8c%2BwUcOuJatVnxYDb8hX3XtFoWZoxZM3LFkpW0wlfmxY29HIvNnQEsV5fQql62IyVqO%2FknPegNtgFfG6wyZ80GtaQRrjcnpdN5eQhvTrNwaG5Tx3S0%2BSH%2BIga9SItA8mZTGs21MZTxKBnMfuJLOsLzLOupL4RJySNeadGyWBT645adAbMO6xnCHvwUNcMmg0cYy4Ubc30vp9NaG7FG1TYueQHve9sAjSBr10xj3QiLhZp1F96PRWJ854ZsIjF8CK07LeYQ4PfJRyCuzTGhEfkJVyAeeMyOKmTy5bkAODbhsw4ZyrGDekz2t3kSnWg5nwWbAXHHcsIm6NDu2J%2FrfMxrRJ7UGgffNvPBQd2TU9UyrzMZyIDu6K3qRja13o0Fw3PaWrrKiWbmbCDwt17d7lSFSlsYyG3zukNKNjS3fa0md%2BhUnzVRPXXqFDVmiZU2HOouV%2Fjn1QRntUV3PdxHRYRUpb5H%2FiD%2FUerIBA%2BEx5AAAAAElFTkSuQmCC" /\x3E [[http://stickwiki.sourceforge.net|WoaS Official Website]]\n\
== Download\n\
Wiki on a Stick can always be downloaded through the official SF.net WoaS project file download service:\n\
\n\
\x3Cbig\x3E[[https://sourceforge.net/projects/stickwiki/files/|Download Wiki on a Stick]]\x3C/big\x3E\n\
== Get support\n\
You can use the [[http://woas.iragan.com/|official WoaS forums]] and the [[http://sf.net/projects/stickwiki/|SF.net WoaS project facilities]].\n\
== Thanks to\n\
This project wouldn\'t be what it is without the help of other people. If you contributed to Wiki on a Stick and your name is not here (or if you do not want it to be listed here), please [[http://sourceforge.net/sendmessage.php?touser=799761|contact the maintainer]].\n\
* *Jeremy Ruston* - the creator of the wonderful [[http://www.tiddlywiki.com/|TiddlyWiki]] that served as inspiration for Wiki on a Stick.\n\
* *Philip O\'Donnel* - the creator of the table syntax and parsing code.\n\
* *Tim Lord*\n\
* *Knut Kohl*\n\
* *Rob Schmersel*\n\
* *Michiel van Everdingen* - [[http://home.versatel.nl/MAvanEverdingen/Code/|original Javascript implementation]] of AES encryption\n\
* *Cyril Mazard* - search feature\n\
* *jimmac* - author of [[http://jimmac.musichall.cz/i.php?i=gorilla-stock|the icon set]] that we are currently using in WoaS\n\
* *martinellison* - transclusion patch\n\
* *Nilton Castillo* - bug fixes and enhancements (original pluggable macro syntax)\n\
* *Little Girl* - assistance with documentation, overall testing, and various improvements\n\
* [[http://weekendtesting.com/archives/833|Europe Weekend Testing]] - provided a testing session for WoaS\n\
* [[http://testconsultant.blogspot.com/|Jeroen Rosink]] - testing of WoaS releases\n\
== Important links\n\
* [[http://sf.net/projects/stickwiki/|SourceForge project home page]] - useful for getting the latest files and contributing to the project.\n\
* [[http://woas.iragan.com/|Official WoaS forums]] - our discussion forums where you can also participate in the decision processes\n\
* [[http://sourceforge.net/tracker/?group_id=155218&atid=794925|SF.net WoaS project bug tracker]] - if you find a bug, post it here\n\
* [[http://sourceforge.net/tracker/?group_id=155218&atid=794928|SF.net WoaS project feature tracker]] - if you have have a suggestion for improvement, post it here\n\
* [[http://www.iragan.com/woas_irc/|Official WoaS IRC Channel]] - #woas room at FreeNode servers\n\
* [[https://lists.sourceforge.net/lists/listinfo/stickwiki-devel|SF.net WoaS Development mailing list]] - for discussion of WoaS development\n\
',
'\x3Cdiv align="center"\x3E\x3Cimg src=\'images/amaselogo.png\' /\x3E\x3C/div\x3E\n\
\n\
= Welcome to AMASE\n\
\n\
The development of UAV command and control technologies can be aided greatly through the use of simulation. The AMASE simulation (AVTAS Multi-agent Simulation Environment) aims to provide a basic simulation environment for the demonstration and testing of UAV control technologies. AMASE brings several vehicle motion, systems, and control models together to form a single, basic-fidelity model for UAV simulation. It is designed to allow for command and control of multiple UAVs using control algorithms within the simulation as well as external control via a network interface.\n\
\n\
== Full UAV Mission-Level Simulation\n\
\n\
AMASE is a simulation toolset for the analysis and demonstration of aircraft automation and autonomy.  AMASE includes the necessary components to create scenarios, simulate aircraft with basic EO/IR cameras, and interact with control algorithms to command aircraft in a scenario. Graphical user interfaces allow AMASE users to evaluate the actions of one or more aircraft at runtime, and the data output feature saves scenario data for post-processing. An integrated network server allows clients to connect to AMASE and send/receive data. AMASE includes three main programs: the simulation, a data playback tool, and a scenario setup tool. \n\
\n\
The AMASE simulation models 5-DOF (coordinated turning) flight dynamics with self-configured performance at a set of design points. AMASE UAVs feature an autopilot that manages coordinated turns, altitude hold, heading hold, vertical speed hold, speed hold (auto-throttle), maintain track in wind fields, loiters (Figure-Eight, Orbit (circular), Racetrack) and waypoint following. Additionally, AMASE UAVs can be equipped with gimbaled and fixed sensors and the simualtion performs footprint analysis for target detection and includes line-of-sight calculation for obscuration of sensors by terrain.\n\
\n\
== A modular and extensible architecture\n\
\n\
AMASE uses the LMCP communication system with the CMASI message set to enable modular development and connectivity with any CMASI-compliant software through a standard network connection. The simulation is a collection of models that are connected to a central data manager which is a central point for dissemination of data from a single external input file and includes a message manager. The message manager passes all messages produced by one component of the simulation to all other components. Internal communications are handled solely by the passing of LMCP messages. When a component produces an LMCP message, all other components attached to the data manager are informed of that message. An LMCP server passes all LMCP messages that are produced in the simulation to any externally connected clients. The server\u2019s responsibility is to serialize internal messages and transmit them to external clients and to de-serialize incoming messages for use inside the simulation.\n\
\n\
AMASE is also a toolkit from which many applications are built.  The AMASE toolkit builds on a set of basic plugins and utilities to provide an application framework, data management, and user interfaces. \n\
\n\
\x3Cdiv class=".woas-notice"\x3E\n\
Please note that AMASE is under constant development.  Different versions of AMASE are in use by several organizations. As such, the documentation may not match exactly with the reader\u2019s version of AMASE.  Please report discrepancies to [[Contact Info]].\n\
\x3C/div\x3E\n\
\n\
== Modeling Capabilities\n\
The AMASE simulation provides a set of models and capabilities to simulate single or multi-aircraft operations.  Some of these capabilities are listed below.\n\
*	Aircraft dynamics and control\n\
**	5-DOF (coordinated turning) flight dynamics\n\
***	Guaranteed performance at a set of design points.\n\
**	Basic UAV autopilot\n\
***	Coordinated turns\n\
***	Altitude Hold\n\
***	Heading Hold\n\
***	Vertical Speed Hold\n\
***	Speed hold (auto-throttle)\n\
***	Autopilot compensation to maintain track in wind\n\
**	Loiter control\n\
***	Figure-Eight\n\
***	Orbit (circular)\n\
***	Racetrack\n\
**	Waypoint following (Handles turn-past, turn-short, and return-to-route turn types)\n\
*	Steady-state wind fields\n\
*	Sensor modeling and control\n\
**	Gimbaled and fixed sensors\n\
**	Footprint analysis for target detection\n\
**	Line-of-sight calculation for obscuration of sensors by terrain\n\
*	Target movement\n\
*	Network server to connect interactive clients\n\
',
'= Search in Wiki\n\
\x3Cinput id="string_to_search" type="text" onfocus="search_focus(true)" onblur="search_focus(false)" /\x3E&nbsp;\x3Cinput class="woas_button" type="button" value="Search" onclick="ssearch_do_search()" /\x3E&nbsp;\x3Cinput class="woas_button" type="button" value="Clear" onclick="woas.ui.clear_search()" /\x3E\n\
\x3Cdiv id="woas_search_results"\x3E&nbsp;\x3C/div\x3E\n\
\x3Cscript type="text/javascript"\x3E\n\
woas._search_load();\n\
\x3C/script\x3E\n\
',
'\x3Cdiv\x3E\x3Cinput id="btn_lock" class="woas_button_top" type="button" value="" onclick="lock_page()" /\x3E\x3C/div\x3E\n\
== AES encryption\n\
Read more about the [[WoaS::Help::Security|embedded AES encryption]] used in Wiki On a Stick.\n\
== Password\n\
Enter your password for AES encryption. The more complex your password is, the more difficult it will be to attack the encryption. It is suggested *not* to use passwords whose textbox color is \x3Cspan style="background-color:red"\x3E&nbsp;red&nbsp;\x3C/span\x3E, and to accept passwords only when the textbox color is \x3Cspan style="background-color:lime"\x3E&nbsp;green&nbsp;\x3C/span\x3E. Punctuation and Mixed case characters will exponentially increase the strength of your password.\n\
\x3Cdl\x3E\x3Cdt\x3E\x3Clabel for="pw1"\x3EEnter password:\x3C/label\x3E\x3C/dt\x3E\x3Cdd\x3E\x3Cinput type="password" id="pw1" style="background-color:red" value="" size="50" onfocus="woas.ui.focus_textbox()" onblur="woas.ui.blur_textbox()" onkeyup="pw_quality()" onkeydown="lock_page(event)" /\x3E&nbsp;\x3Cspan id="txtBits"\x3E&nbsp;\x3C/span\x3E\x3C/dd\x3E\x3Cdt\x3E\x3Clabel for="pw2"\x3ERe-enter password:\x3C/label\x3E\x3C/dt\x3E\x3Cdd\x3E\x3Cinput type="password" id="pw2" value="" size="50" onfocus="woas.ui.focus_textbox()" onblur="woas.ui.blur_textbox()" onkeydown="lock_page(event)" /\x3E\x3C/dd\x3E\x3C/dl\x3E\\\n\
\x3Cscript type="text/javascript"\x3E\n\
	_lock_page();\n\
\x3C/script\x3E\n\
',
'== AES encryption\n\
[[http://en.wikipedia.org/wiki/Advanced_Encryption_Standard|AES]] 256-bit high security data encryption standard is supported to protect a single page or groups of them.\n\
\n\
WoaS has two different interfaces for encryption passwords, namely one for encryption (called *Locking*) and one for decryption (called *Unlocking*).\n\
== Encryption\n\
The page encryption interface shows a colored meter for estimated password quality; the encryption password is not stored in your saved files (true AES encryption is used).\n\
\x3C\x3C\x3Cwoas.note: *If you forget the password there is no way to retrieve it or your data.*\x3E\x3E\x3E\n\
Click on the /lock/ icon in the navigation bar to encrypt the page being viewed. The page locking interface has two password boxes (the second for verification); the background color of the first box provides a hint about estimated password strength.\n\
\n\
Once you\'ve chosen and typed in your password, click the *Lock* button to encrypt the page.\n\
\n\
When encrypting additional pages during a session, you\'ll be offered to use the same password you used to encrypt the first page. Accept by pressing the *OK* button or decline by pressing the *Cancel* button. If you decline, the password interface will open, allowing you to set a new password for the page. There is no limit to how many passwords you can use.\n\
== Decryption\n\
Click the *Set password* icon in the navigation bar to set the decryption password used for the next page.\n\
\n\
The password for decrypting a page (or pages) is cached so that you only need to enter it once per session. If you close or reload the wiki, you will need to reenter the password to work with the encrypted page(s). To disable the password cache, check the box for *Do not temporarily cache the AES key* in the wiki [[WoaS::Help::Special::Options|Options]]. If you\'ve used more than one password for encrypting your pages, you\'ll need to enter the password to unlock each encrypted page.\n\
== Security level\n\
Security is never absolute. Data encrypted with these pages might be compromised in a variety of ways, including but not limited to the following:\n\
\n\
* User-generated passwords are weak by nature (PBKDF2 will be used in a future version)\n\
* You have not disabled the AES key cache, so when you enter the password for the first time other users (if not you) will be able to see encrypted pages and could possibly get your key\n\
* WoaS uses random numbers generated by the browser itself using local time; if someone was somehow able to gain access to the particular time used they could perhaps discover the key (user-generated entropy will be used in a future version)\n\
* Your Web browser and/or Javascript interpreter may contain bugs or deliberate security violations which report activity on your computer back to some other Internet site\n\
* Some other applet running on another page in your browser, perhaps without you being aware of its existence, is spying on other windows.\n\
* Some other "spyware" application running on your computer may have compromised your system\'s security and be snooping on your activity.\n\
* The implementation of the encryption may contain a bug that makes its results insecure, Wiki on a Stick is open-source; you can judge for yourself whether the tool merits your confidence.\n\
* Your computer\'s security may have been compromised physically; when\'s the last time you checked that a bug that transmits your keystrokes and/or screen contents to that white van parked down the street wasn\'t lurking inside your computer cabinet?\n\
\n\
Apart from the above, your normal usage of encrypted pages can be considered secure.\n\
',
'\x3Cdiv class="woas_no_option"\x3E\x3Cinput class="woas_button_top" type="button" onclick="save_options()" value="Save options" /\x3E\x3C/div\x3E\n\
= Options\n\
\x3Cfieldset id="S10406" class="woas_input_wrap"\x3E\x3Clegend\x3EUser Interface\x3C/legend\x3E\\\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_auto_links" onclick="woas.config.auto_links = d$.checked(\'cb_auto_links\')" /\x3EAutomatically convert URLs to hyperlinks\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_key_cache" onclick="woas.config.key_cache = !d$.checked(\'cb_key_cache\')" /\x3EDo not temporarily cache the AES key\x3C/label\x3E\x3Cbr id="woas_hidden_break" /\x3E\x3Clabel class="woas_no_option"\x3E\x3Cinput type="checkbox" id="cb_dblclick_edit" onclick="woas.config.dblclick_edit = d$.checked(\'cb_dblclick_edit\')" /\x3EDouble click to edit pages/menu\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_debug_mode" onclick="woas.config.debug_mode = d$.checked(\'cb_debug_mode\');woas._set_debug(woas.config.debug_mode);d$(\'cb_debug_closed\').disabled=!woas.config.debug_mode" /\x3EEnable debug mode\x3C/label\x3E&nbsp;&nbsp;\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_debug_closed" class="woas_input_wrap_inline" onclick="woas.config.debug_closed = d$.checked(\'cb_debug_closed\')" /\x3EStart with console closed\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_fixed_menu" onclick="var fl=d$.checked(\'cb_fixed_menu\');woas.config.fixed_menu=fl;woas.ui.set_menu(fl)" /\x3EFixed menu\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_fixed_header" onclick="var fl=d$.checked(\'cb_fixed_header\');woas.config.fixed_header=fl;woas.ui.set_header(fl)" /\x3EFixed navigation bar\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_sort_tags" onclick="woas.config.sort_tags = d$.checked(\'cb_sort_tags\')" /\x3ESort tags in tag display\x3C/label\x3E\n\
\x3Clabel class="woas_no_option"\x3E\x3Cselect id="sel_menu_link" onChange="woas.config.menu_link=this.selectedIndex"\x3E\x3Coption\x3EAlways ask\x3C/option\x3E\x3Coption\x3EAlways\x3C/option\x3E \x3Coption\x3ENever\x3C/option\x3E\x3C/select\x3E Create a main menu link to newly created pages\x3C/label\x3E\\\n\
\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S2324" class="woas_input_wrap"\x3E\x3Clegend\x3ESyntax\x3C/legend\x3E\\\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_new_tables_syntax" onclick="woas.config.new_tables_syntax = d$.checked(\'cb_new_tables_syntax\')" /\x3EEnhanced tables syntax\x3C/label\x3E\\\n\
\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S2219" class="woas_input_wrap woas_no_option"\x3E\x3Clegend\x3ESaving\x3C/legend\x3E\\\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_save_on_quit" onclick="woas.config.save_on_quit = d$.checked(\'cb_save_on_quit\')" /\x3EAutomatically save options before quitting (if changed)\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_safe_mode" onclick="woas.config.safe_mode = d$.checked(\'cb_safe_mode\')" /\x3EEnable safe mode with embedded scripts and plugins not executed (/requires reload/)\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_allow_diff" onclick="woas.config.allow_diff = d$.checked(\'cb_allow_diff\')" /\x3EMake merge/diff of WoaS XHTML/WSIF data source easier\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_store_mts" onclick="var r = woas.config.store_mts = d$.checked(\'cb_store_mts\'); woas.ui.display({no_mts:!r})" /\x3EStore and display last modified timestamp\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="cb_rem_history" onclick="woas.config.nav_history = d$.checked(\'cb_rem_history\')" /\x3EStore current page and navigation history\x3C/label\x3E\\\n\
\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S9272" class="woas_input_wrap woas_no_option"\x3E\x3Clegend\x3EWSIF settings\x3C/legend\x3E\\\n\
\x3Cdiv class="woas_input_wrap_left"\x3EPages are stored internally if /WSIF data source/ is blank. *Existing internal pages will be deleted if /WSIF data source/ is changed from blank to an external source, and the external source will be overwritten with this wiki\'s content if it already exists!*\n\
\n\
If the /Use multiple files for WSIF data source/ option is being used (creating one WSIF file for each page) then disabling the option will not remove existing WSIF files, though the /WSIF data source/ index file will be overwritten with the full page content.\n\
\n\
The path may be entered in Windows or UNIX format. *Any directories in the path must exist if you are not using a Mozilla browser.*\x3C/div\x3E\n\
\x3Cdiv class="woas_input_wrap_left" style="background-color:#FAFAFF; *background-color:#FFF; *border: solid black 1px; padding:10px; margin-top:10px; margin-bottom:10px"\x3E\n\
\x3Clabel\x3ERelative path to WSIF data source, including filename: \x3Cinput class="woas_input_wrap_inline" id="txt_wsif_ds" type="text" size="60" value="" /\x3E\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput class="woas_input_wrap_no_left" type="checkbox" id="cb_wsif_ds_multi" onclick="woas.ui.wsif_ds_multi = this.checked" /\x3EUse multiple files for WSIF data source\x3C/label\x3E\n\
\n\
\x3Cinput class="woas_button woas_input_wrap_no_left" type="button" onclick="woas.ui.wsif_ds(d$(\'txt_wsif_ds\'), d$(\'cb_wsif_ds_multi\'), true)" value="Change data source" /\x3E&nbsp; /Data source changes will not be used unless confirmed with the /Change data source /button./\n\
\x3C/div\x3E\n\
\x3Clabel class="woas_input_wrap_left"\x3EWSIF author: \x3Cinput class="woas_input_wrap_inline" id="txt_author" type="text" size="30" value="" onchange="woas.config.wsif_author=this.value" /\x3E\x3C/label\x3E\\\n\
\x3C/fieldset\x3E\\\n\
\x3Cdiv class="woas_no_option"\x3E\\\n\
\x3Cfieldset id="S15410" class="woas_input_wrap" style="border-color:#f00"\x3E\x3Clegend\x3EPermanent changes\x3C/legend\x3E\\\n\
\x3Cinput class="woas_button_ro" type="button" onclick="ro_woas()" value="Prevent edits" /\x3E&nbsp; /Caution: to re-enable editing you will have to manually edit this WoaS file/\\\n\
\x3C/fieldset\x3E\\\n\
\x3C/div\x3E\n\
\x3Cstyle\x3E\n\
#woas_hidden_break {\n\
	display: block\n\
}\n\
.woas_ro .woas_no_option, .woas_ro #woas_hidden_break {\n\
	display: none\n\
}\n\
\x3C/style\x3E\n\
\x3Cscript type="text/javascript"\x3E\n\
d$("cb_allow_diff").checked = woas.bool2chk(woas.config.allow_diff);\n\
d$("cb_rem_history").checked = woas.bool2chk(woas.config.nav_history);\n\
d$("cb_store_mts").checked = woas.bool2chk(woas.config.store_mts);\n\
d$("cb_new_tables_syntax").checked = woas.bool2chk(woas.config.new_tables_syntax);\n\
d$("cb_auto_links").checked = woas.bool2chk(woas.config.auto_links);\n\
d$("cb_sort_tags").checked = woas.bool2chk(woas.config.sort_tags);\n\
d$("cb_key_cache").checked = woas.bool2chk(!woas.config.key_cache);\n\
d$("cb_dblclick_edit").checked = woas.bool2chk(woas.config.dblclick_edit);\n\
d$("cb_debug_mode").checked = woas.bool2chk(woas.config.debug_mode);\n\
d$("cb_debug_closed").checked = woas.bool2chk(woas.config.debug_closed);\n\
d$("cb_save_on_quit").checked = woas.bool2chk(woas.config.save_on_quit);\n\
d$("cb_safe_mode").checked = woas.bool2chk(woas.config.safe_mode);\n\
d$("cb_fixed_header").checked = woas.bool2chk(woas.config.fixed_header);\n\
d$("cb_fixed_menu").checked = woas.bool2chk(woas.config.fixed_menu);\n\
d$("sel_menu_link").selectedIndex = woas.config.menu_link;\n\
\n\
if (woas.browser.ie6) d$("cb_fixed_header").disabled =  d$("cb_fixed_menu").disabled = true;\n\
\n\
// multi must be set by WSIF loader; it must not be a config setting\n\
woas.ui.wsif_ds_multi = woas.wsif.ds_multi;\n\
// set datasource and multi checkbox\n\
woas.ui.wsif_ds(d$(\'txt_wsif_ds\'), d$(\'cb_wsif_ds_multi\'));\n\
d$("txt_author").value = woas.config.wsif_author;\n\
\n\
d$("txt_wsif_ds").onfocus = d$("txt_author").onfocus = woas.ui.focus_textbox;\n\
d$("txt_wsif_ds").onblur = d$("txt_author").onblur = woas.ui.blur_textbox;\n\
\x3C/script\x3E\n\
',
'A summary of WoaS deprecated syntax; you should not use deprecated syntax because it will be declared /unsupported/ in a future release of WoaS. The red examples demonstrate deprecated syntax and the green examples demonstrate syntax currently accepted by the wiki.\n\
== Headings\n\
Headings using exclamation marks are deprecated:\x3Cspan class="bad_syntax"\x3E{{{\n\
! Heading level 1\n\
!! Heading level 2\n\
!!! Heading level 3\n\
!!!! Heading level 4\n\
!!!!! Heading level 5\n\
!!!!!! Heading level 6\n\
}}}\x3C/span\x3E\n\
Headings using equal signs are accepted:\x3Cspan class="good_syntax"\x3E{{{\n\
= Heading level 1\n\
== Heading level 2\n\
=== Heading level 3\n\
==== Heading level 4\n\
===== Heading level 5\n\
====== Heading level 6\n\
}}}\x3C/span\x3E\n\
== Inline scripts\n\
HTML script tags with no type attribute are not supported:\x3Cspan class="bad_syntax"\x3E{{{\n\
\x3Cspan class="bad_syntax"\x3E\n\
}}}\x3C/span\x3EHTML script tags with the *text/javascript* type attribute are accepted:\x3Cspan class="good_syntax"\x3E{{{\n\
\x3Cscript type="text/javascript"\x3E...\x3C/script\x3E\n\
}}}\x3C/span\x3EThis is not enforced by WoaS wiki parser but is instead a correct XHTML practice.\n\
== Lists\n\
Unordered lists using plus signs are not supported:\x3Cspan class="bad_syntax"\x3E{{{\n\
+ unordered list item\n\
+ unordered list item\n\
+ unordered list item\n\
}}}\x3C/span\x3E\n\
Unordered lists using asterisks are accepted:\x3Cspan class="good_syntax"\x3E{{{\n\
* unordered list item\n\
* unordered list item\n\
* unordered list item\n\
}}}\x3C/span\x3E\n\
== Pre tags\n\
HTML pre tags surrounding raw or preformatted text are not supported:\x3Cspan class="bad_syntax"\x3E{{{\n\
\x3Cpre\x3Eraw or preformatted text\x3C/pre\x3E\n\
}}}\x3C/span\x3E\n\
Nowiki brackets surrounding raw or preformatted text are accepted:\x3Cspan class="good_syntax"\x3E\x3Cpre style="background-color: #F5F5F5; border: 1px solid #808080; font-family: monospace; padding-right: 0.27em; padding-left: 0.4em;"\x3E{\x3C!-- --\x3E{{raw or preformatted text}}\x3C!-- --\x3E}\n\
\n\
{\x3C!-- --\x3E{{\n\
raw or preformatted text\n\
}}\x3C!-- --\x3E}\x3C/pre\x3E\x3C/span\x3E\n\
== Rulers\n\
Horizontal rules using 3 hyphens are deprecated:\x3Cspan class="bad_syntax"\x3E{{{\n\
---\n\
}}}\x3C/span\x3E\n\
Horizontal rules using 4 or more hyphens are accepted:\x3Cspan class="good_syntax"\x3E{{{\n\
----\n\
}}}\x3C/span\x3E\n\
== Tags\n\
=== Single tags\n\
Tags in the Tag:: and the Tags:: [[WoaS::Help::Namespaces|reserved namespace]] are accepted:\x3Cspan class="good_syntax"\x3E\n\
{{{\n\
[[Tag::some tag]]\n\
[[Tags::some tag]]\n\
}}}\x3C/span\x3E\n\
=== Multiple tags\n\
Tags separated by pipes in the Tag::, [[Tagged::]], or Tags:: namespace are deprecated:\x3Cspan class="bad_syntax"\x3E\n\
{{{\n\
[[Tag::some tag|other tag|another tag]]\n\
[[Tagged::some tag|other tag|another tag]]\n\
[[Tags::some tag|other tag|another tag]]\n\
}}}\x3C/span\x3E\n\
Tags separated by commas in the Tag::, [[Tagged::]], and Tags:: namespace are accepted:\x3Cspan class="good_syntax"\x3E\n\
{{{[[Tag::some tag, other tag, another tag]]\n\
[[Tags::some tag, other tag, another tag]]\n\
[[Tagged::some tag, other tag, another tag]]\n\
}}}\x3C/span\x3E\n\
\x3Cstyle type="text/css"\x3E\n\
.bad_syntax {\n\
  color: #f00; /* red */\n\
  font-weight: bold;\n\
}\n\
.good_syntax {\n\
  color: #008000; /* green */\n\
  font-weight: bold;\n\
}\n\
\x3C/style\x3E\n\
',
'/The [[Special::Options]] page currently stores all options within the WoaS HTML file when the/ Save options /button is clicked; they are never stored inside an external datasource [[WoaS::Help::WSIF|WSIF]] file. Currently the options will also be saved whenever a page is edited, though this will be changed in a future version./\n\
==User Interface\n\
===Automatically convert URLs to hyperlinks\n\
converts URLs to [[WoaS::Help::Links|external links]] when the page content is displayed.\n\
===Do not temporarily cache the AES key\n\
Clears the [[WoaS::Help::Security|AES key]] immediately after encrypting or decrypting a page to prevent possible unauthorized access. Using this option will require the key to be entered each time you want to read an encrypted page.\n\
===Double-click to edit pages/menu\n\
Opens the editor when the main text area or menu are double-clicked.\n\
===Enable debug mode\n\
Enables display of the debug console at the bottom of the main text area and allows the wiki to log its history. This can be useful if you asking are for help or reporting a problem.\n\
===Start with console closed\n\
Ensures that the debug console will start closed. This option is disabled if /Enable debug mode/ is not selected.\n\
===Fixed menu\n\
Fixes the menu in place while allowing the page to scroll. This option is disabled in IE6.\n\
===Fixed navigation bar\n\
Fixes the navigation bar in place while allowing the page to scroll. This option is disabled in IE6.\n\
===Sort tags in tag display\n\
Sorts the tags in the tag display alphabetically.\n\
===Create a main menu link to newly created pages\n\
WoaS is able to put a link to newly created pages in the main menu. Whether or not it does so depends on the setting of this option. The link will not be created if the new page is cancelled.\n\
* /Always Ask/ prompts for a decision each time a new page is created\n\
* /Always/ creates a link without asking\n\
* /Never/ disables this function\n\
== Syntax\n\
===Enhanced tables syntax\n\
Tables will use the enhanced [[WoaS::Help::Tables|table syntax]].\n\
== Saving\n\
===Automatically save options before quitting (if changed)\n\
Saves changes to options automatically when closing the wiki. This will not happen if you are just reloading the file.\n\
===Enable safe mode with embedded scripts and plugins not executed (/requires reload/)\n\
Prevents the wiki from executing [[WoaS::Help::Javascript|embedded scripts]] and [[WoaS::Help::Plugins|plugins]].\n\
===Make merge/diff of WoaS XHTML/WSIF data source easier\n\
Adds a [[WoaS::Help::Join lines of text|backslash]] and line-end character (\\\\n) to the end of every line of page text. This breaks the text into multiple lines, instead of it being one page-length line, making it easier for source code revision tools (like SVN or git) and merge tools to mark and show changes efficiently.\n\
===Store and display last modified time-stamp\n\
Allows the wiki to store the last time each page was changed and display it as a time-stamp beneath the main text area.\n\
===Store current page and navigation history\n\
Remembers the most recent back history and automatically opens the most recently saved page whenever you load the wiki into a browser.\n\
== WSIF Settings\n\
WoaS is most often used as a single-file wiki, with all of it\'s content inside one self-modifying XHTML file, but it can also be used with external content files, called [[WoaS::Help::WSIF|WSIF]] files. It can use a single WSIF file containing all of the wiki\'s page content, or a single WSIF index file that links to the WSIF files of individual pages. Everything works the same whichever way it is used.\n\
\n\
If you just want to use a WSIF file for backing up or sharing your data with others you should use [[WoaS::Help::Special::ExportWSIF|Special::ExportWSIF]] instead as the WoaS file is then not altered.\n\
===Relative path to WSIF data source, including filename\n\
This is the relative path and name of the file the wiki should use to save and retrieve data. A relative path is one that starts in the same directory the WoaS file is in; {{{temp/file.wsif}}} is a relative path, {{{/temp/file.wsif}}} is not; {{{c:\\temp\\file.wsif}}} and {{{c:temp\\file.wsif}}} are also incorrect. The file name can have any extension or none at all, but the /wsif/ extension will let you know that it\'s a WoaS data source file. The path may be entered in Windows or UNIX format, but will be converted to the correct format upon entry (it is stored in the WoaS file in UNIX format).\n\
\n\
Providing a filename causes the wiki to create a WSIF file by that name and use that file to store and retrieve all page data (configuration options are currently always stored in the WoaS HTML file, not in a WSIF file). If just a filename is entered the file will be created inside the directory the WoaS file is in. The path can additionally specify a directory path relative to the location of the wiki. WoaS will create the specified subdirectory only if you are using a Gecko-based browser like Firefox. If you are using a different browser you must create the subdirectory yourself before saving the file. (As of this writing, the best browser to use with WoaS is *Firefox*; while [[WoaS::Help::Requirements|all major browsers]] can be used to read, edit, and save a WoaS file, other browsers cannot currently import or export binary files, such as image files. This limits some capabilities, like embedding images or exporting them to a binary image file.)\n\
\x3C\x3C\x3Cwoas.note: If you enter the name of an existing file that file will be overwritten when /Change data source/ is clicked; any associated files will also be overwritten if /multiple files/ mode is selected.\x3E\x3E\x3E\n\
The data source name will be used as the index page name when using multiple files as a data source.\n\
\n\
The box is blank by default. Leaving the box blank, or deleting an existing filename from the box, causes the wiki to save all the currently loaded data to itself and retrieve all data from itself. Deleting the filename from the box does not delete any files.\n\
===Use multiple files in WSIF data source\n\
Causes the wiki to create individual WSIF files for each page. The pages will be automatically named by page number in their order of creation. An index page with the WSIF data source filename will be created containing a list of the numbered file names and their corresponding wiki page names. WoaS will use this file to load data and save edits to the correct file.\n\
\x3C\x3C\x3Cwoas.note: The two WSIF data source settings described above will *not* be used or saved unless you confirm the change with the /Change data source/ button. WoaS will then describe the impact of the changes you are about to make so you can change your mind if you want to by pressing cancel.\x3E\x3E\x3E\n\
===WSIF Data author\n\
This is the name of the author as displayed in exported WSIF files. Replace the default name with your own to be credited as the author of the file(s). Deleting the contents of the box prevents the author line from being added to WSIF files.\n\
==Permanent changes\n\
===Prevent edits\n\
Clicking this button puts the wiki into read-only mode. The edit icon is removed and all editing is disabled. To re-enable editing, the wiki must be [[WoaS::Help::Wiki is read-only|manually edited]].\n\
\n\
If the file is already in read-only mode the /Prevent Edits/ button is not displayed.\n\
',
'\x3Cdiv\x3E\x3Cinput class="woas_button_top" type="button" value="Embed" onclick="woas._embed_process(\'%1\')" /\x3E\x3C/div\x3E\n\
= Embed %1\n\
\x3Cinput id="filename_" type="file" /\x3E\n\
',
'\x3Cdiv\x3E\x3Cinput class="woas_button_top" title="Import a plugin" value="Import plugin..." onclick="woas.go_to(\'Special::ImportWSIF\')" type="button" /\x3E\x3Cinput class="woas_button_top" title="Create a new plugin" value="Create plugin..." onclick="_woas_new_plugin()" type="button" /\x3E\x3C/div\x3E\n\
= Installed plugins',
'[[Special::TOC]]\n\
= Wiki on a Stick History\n\
== This version\n\
This WoaS uses the 0.12.0 code as a base for various fixes. See [[Improvements]].\n\
== Versions 0.01 &tilde; 0.04\n\
\x3Csub\x3Eby Andr\u00e9 Wagner\x3C/sub\x3E\n\
\n\
As they say, /"necessity is the mother of invention"/. I needed a way to store information in a tree-like structure, but every software I tested felt like it was something missing. I tested a few mindmap software, tree structure software and personal wikis, but they were too complicated to install; I didn\'t yet have what I was looking for, or the tool wasn\'t closs-platform.\n\
\n\
The closest thing I found was [[http://www.tiddlywiki.com/|TiddlyWiki]], but it still wasn\'t perfect: it was too much blog-like, and what I needed was something wiki-like. So TiddlyWiki served as inspiration for the software I was about to create (I even used their saving routines).\n\
\n\
The core part of the code was written in one rainy afternoon. A few days later (after correcting most problems) I released it and the feedback I received was much more than I could ever expect. I guess that many other people had my same needs  :-) So this gave me motivation to continue working on Wiki on a Stick and to release three more versions.\n\
=== The principles\n\
Since the beginning I followed two basic principles: *simplicity* and *stability*. For simplicity I mean that the software should be easy enough for anyone to use, and the interface should be as plain as possible. And for stability I mean that the user data is sacred above all things, and the user should never loose his data, no matter what happens. I think these were the two facts that brought the good acceptance from the users.\n\
\n\
Unfortunatly, the duties of my graduation thesis made me stop working on WoaS and the software became dormant for a couple of months. It made me feel bad, since the mailing lists were at full throttle, with many people requesting features and sending patches that I couldn\'t even test.\n\
\n\
So I was very glad when Daniele offered himself to take over the task of managing the project. He did a great work and now WoaS is a much more rich application, with a even greater userbase. It feels really nice to see that people all around the world are using the software I created, and my desire is to see that WoaS grows in quality, features and userbase, and to remain a simple yet useful tool to everyone.\n\
== Versions 0.9.x\n\
\x3Csub\x3Eby Daniele C.\x3C/sub\x3E\n\
\n\
When I first found WoaS I felt that this software has a great potential; my first contribute to WoaS was to resolve all the bug tracker items and review the patches; the result was put into a v0.04G released in a SF.net patches tracker item (as attachment). That modified version was mostly a bug-fix and feature-fix modification, with small new features like custom keys for navigation and edits cancelling. V0.04G also missed the import feature (I forgot to add it back) and had a nasty double-click to edit feature which was not really good. That was my experimentation, I did not expect people to really use my modified version but since Andr\u00e9 had no time to review it, people was actually starting to use it.\n\
\n\
Some time later I took courage and asked to take-over the project; Andr\u00e9 Wagner kindly added me to the project as a developer and a project admin and I could start working on WoaS for real.\n\
\n\
My first big project management change was to switch to [[http://subversion.tigris.org/|Subversion (SVN)]] for the versioning of all our WoaS files; development could this way be fully documented and followed "live" by the mailing list (formerly google group) partecipants, which are the first solid community gathered around WoaS.\n\
\n\
Version 0.9B was the first official version which I worked on. My first big change was to have storage of pages not in content-escaped hidden divs but as Javascript strings; this brought more speed to the page loading process. I also had to solve some problems inherent to the double file vs single file compatibility (WoaS can since then work with the 2-files version and single file version) and some IE saving issues, but finally the result was good enough.\n\
\n\
A lot of features and improvements have been implemented during the (still current) v0.9.x development cycle, without never slowing down some parts of WoaS for each new feature implemented (further speed optimizations will be engineered when the codebase is stable enough); we are as always gathering the users\' feedback to add usability and more powerful features to WoaS. Such features must of course be coherent with WoaS principles and base philosophy.\n\
=== Object orienting\n\
Wiki on a Stick codebase has been rewritten as object-oriented in order to be more maintanable and modular (the development version contains multiple Javascript source files which are as always merged into one before releases). Such process is not yet complete and is being carried out during the 0.12.x development.\n\
== 0.10.x\n\
Development of 0.9.7B was stale and WoaS was getting full of little bugs which prevented it from being successfully used; during last months of 2009 and first months of 2010 WoaS got new blood with 0.10.x releases.\n\
Some of the best additions were [[WoaS::Help::WSIF|WSIF format]] and a pluggable macro syntax, but finally the product had reached the stability which its users deserved and exited its Beta status to enter a Production development stage.\n\
== 0.11.x\n\
The 0.11.x development stage is focusing new features and fixing old bugs; there have been many new important enchancements like access keys.\n\
== 0.12.x\n\
During development of 0.12.0 plugins support has been added and code has been re-organized for modularity.\n\
',
'\x3Cdiv\x3E\x3Cinput class="woas_button_top" type="button" value="Export XHTML" onclick="woas.export_wiki()" /\x3E\x3C/div\x3E\n\
= Export content into linked XHTML files\n\
\x3Cfieldset id="S1613" class="woas_input_wrap"\x3E\x3Clegend\x3EPaths\x3C/legend\x3E\\\n\
\x3Cdiv class="woas_input_wrap_left" style="margin-bottom:5px"\x3E*Directory paths must exist if using a non-Mozilla browser. If exported files already exist they will be overwritten.*\x3C/div\x3E\n\
\n\
\x3Clabel class="woas_input_wrap_left"\x3EDirectory for XHTML files: \x3Cinput class="woas_input_wrap_inline" id="woas_ep_xhtml" type="text" size="80" /\x3E\x3C/label\x3E\n\
\x3Clabel class="woas_input_wrap_left"\x3EDirectory for embedded pictures: \x3Cinput class="woas_input_wrap_inline" id="woas_ep_img" type="text" size="80" /\x3E\x3C/label\x3E\n\
\x3Clabel class="woas_input_wrap_left"\x3EExtension for generated XHTML files: \x3Cinput class="woas_input_wrap_inline" id="woas_ep_ext" type="text" size="8" /\x3E\x3C/label\x3E\n\
\x3Clabel for="woas_cb_index_main"\x3E\x3Cinput type="checkbox" id="woas_cb_index_main" checked="checked"\x3EName the main page /index/ (plus file extension above)\x3C/label\x3E\n\
\x3Clabel for="woas_cb_unix_norm"\x3E\x3Cinput type="checkbox" id="woas_cb_unix_norm" checked="checked"\x3EApply UNIX-style normalization to generated filenames (all lowercase letters; non-alphanumeric characters replaced with underscores)\x3C/label\x3E\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S19285" class="woas_input_wrap"\x3E\x3Clegend\x3ECustom page scripts\x3C/legend\x3E\x3Clabel for="woas_cb_js_ign"\x3E\x3Cinput type="radio" id="woas_cb_js_ign" name="woas_cb_js" checked="checked"\x3EDo not export Javascript\x3C/label\x3E\n\
\x3Clabel for="woas_cb_js_exp"\x3E\x3Cinput type="radio" id="woas_cb_js_exp" name="woas_cb_js"\x3EExport Javascript as-is\x3C/label\x3E\n\
\x3Clabel for="woas_cb_js_dyn"\x3E\x3Cinput type="radio" id="woas_cb_js_dyn" name="woas_cb_js"\x3ERun before exporting, but do not export the Javascript\x3C/label\x3E\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S9592" class="woas_input_wrap"\x3E\x3Clegend\x3EOther options\x3C/legend\x3E\x3Clabel class="woas_input_wrap_left"\x3EMETA author (optional): \x3Cinput class="woas_input_wrap_inline" id="woas_ep_author" type="text" size="30" value="" /\x3E\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_sep_css" checked="checked"\x3EExport CSS into shared file\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_export_menu" checked="checked"\x3EExport menus\x3C/label\x3E\x3C/fieldset\x3E\\\n\
\x3Cscript type="text/javascript"\x3E\n\
var path = woas.ROOT_DIRECTORY + "export" + woas.DIRECTORY_SEPARATOR;\n\
d$(\'woas_ep_xhtml\').value = path;\n\
d$(\'woas_ep_img\').value = path;\n\
d$(\'woas_ep_ext\').value = woas.exporter._default_ext;\n\
\n\
d$(\'woas_ep_xhtml\').onfocus = d$(\'woas_ep_img\').onfocus = d$(\'woas_ep_ext\').onfocus = woas.ui.focus_textbox;\n\
d$(\'woas_ep_xhtml\').onblur = d$(\'woas_ep_img\').onblur = d$(\'woas_ep_ext\').onblur = woas.ui.blur_textbox;\n\
d$(\'woas_ep_author\').value = woas.config.wsif_author;\n\
\x3C/script\x3E\n\
',
'= Special::License\n\
Retrieved from [[http://www.gnu.org/licenses/gpl2.txt]]:\n\
\n\
\x3Ciframe border="0" width="100%" height="300" src="http://www.gnu.org/licenses/gpl2.txt"\x3E\x3C/iframe\x3E\n\
',
'Lines that do not start with \'$\' are ignored\n\
\n\
$JS  Javascript\n\
',
'\x3Cdiv\x3E\x3Cinput class="woas_button_top" type="button" value="Export WSIF" onclick="woas.export_wiki_wsif()" /\x3E\x3C/div\x3E\n\
= Export to [[WoaS::Help::WSIF|WSIF]] format\n\
\x3Cfieldset id="S28565" class="woas_input_wrap"\x3E\x3Clegend\x3EFile generation options\x3C/legend\x3E\x3Cdiv style="margin-bottom:5px" class="woas_input_wrap_left"\x3E*Directory path must exist if using a non-Mozilla browser. If file exists it will be overwritten, along with any associated files if exporting to multiple files.* Filename is the name of the page index file if /Export as multiple WSIF files/ is selected.\x3C/div\x3E\n\
\n\
\x3Clabel class="woas_input_wrap_left"\x3ERelative path for WSIF file, including filename: \x3Cinput class="woas_input_wrap_inline" id="woas_ep_path" type="text" size="60" value="" onblur="woas.ui.wsif_ds(this);woas.ui.blur_textbox()" /\x3E\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_multi_wsif" /\x3EExport as multiple WSIF files (instead of saving all pages to a single wsif file)\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_all_wsif"\x3EInclude ALL pages from this WoaS (instead of only user created pages)\x3C/label\x3E\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S9592" class="woas_input_wrap"\x3E\x3Clegend\x3EOther options\x3C/legend\x3E\x3Clabel class="woas_input_wrap_left"\x3EAuthor: \x3Cinput class="woas_input_wrap_inline" id="woas_ep_author" type="text" size="30" value="Anonymous" /\x3E\x3C/label\x3E\n\
\x3Cscript type="text/javascript"\x3E\n\
d$(\'woas_ep_path\').value = "wsif" + woas.DIRECTORY_SEPARATOR + woas.wsif.DEFAULT_INDEX;\n\
d$(\'woas_ep_author\').onfocus = d$(\'woas_ep_path\').onfocus = woas.ui.focus_textbox;\n\
d$(\'woas_ep_author\').onblur = woas.ui.blur_textbox;\n\
d$(\'woas_ep_author\').value = woas.config.wsif_author;\n\
\x3C/script\x3E\n\
',
'*W*iki on a *S*tick *I*nterchange *F*ormat is the preferred format for exporting full WoaS data into a single file and share it with whoever you like.\n\
== Format description\n\
WSIF format is similar to MIME email attachments format; each line is formatted like an /email header/ definition:\n\
\n\
{{{header.name: header-value}}}\n\
\n\
All WSIF content must be ASCII, so /header-value/ must be ECMA-escaped when necessary; this corresponds to escaping slashes "\\" to "\\\\" and any UTF-8 sequence to the corresponding "\\u0000" string, where /0000/ is the lowercase hexadecimal value of the UTF-8 character (like in ECMAScript).\n\
\n\
WSIF files can contain custom headers, given that the following namespaces are currently reserved for official WSIF format support:\n\
* *wsif*\n\
* *woas*\n\
\n\
For example you could define a new namespace for header definitions called /custom/:\n\
\n\
{{{\n\
custom.x: 100\n\
custom.y: 200\n\
custom.content: Hello world!\n\
}}}\n\
It is then up to you to parse such header-value couples and give them proper representation.\n\
== Inline boundaries\n\
A line starting with two dashes (/--/) introduces an *inline boundary*, which is a properly encoded snippet.\n\
\n\
Example boundary:\n\
\n\
{{{\n\
--my-random-id\n\
this is the inline snippet\n\
--my-random-id\n\
}}}\n\
/my-random-id/ must be a (usually random) string *unique inside the boundary content*, but it does not need to be unique inside the whole WSIF file, which must be read sequentially (like in a state machine).\n\
= wsif namespace\n\
The *wsif.* namespace currently defines only an information header:\n\
\n\
* *wsif.version* - WSIF format version into which content is offered\n\
* *wsif.generator* - program/library used to generate WSIF content\n\
Version 1.1.0 and above are currently supported.\n\
= woas namespace\n\
The *woas.* namespace defines general WoaS content properties and specific WoaS pages; the following headers are defined for general context:\n\
\n\
* *woas.version* - version of WoaS used to produce the WSIF file\n\
* *woas.pages* - total count of WoaS pages stored inside WSIF file\n\
\n\
The following are header definitions specific for WoaS pages:\n\
\n\
* *woas.page.title* - ECMA-escaped page title; this header has a special meaning because it is the page start marker inside the state machine; it is suggested that WSIF implementations write it as first header for page definition stanzas;\n\
* *woas.page.attributes* - a positive integer value in decimal format specifying the page attributes;\n\
* *woas.page.last_modified* - a positive integer value in decimal format representing seconds lasted from the UTC epoch up to last modified time; this header is defined only if data is available from WoaS;\n\
* *woas.page.length* - content length of the inline snippet; only inline files define it; this is not the decoded page length but the length of the content inside the inline boundaries;\n\
* *woas.page.original_length* - real page length as seen by WoaS; it is currently defined only for encrypted pages;\n\
* *woas.page.encoding* - snippet encoding format, see the *Encoding* section below;\n\
* *woas.page.disposition* - tells whether page is /inline/ or /external/;\n\
* *woas.page.boundary* - string used for inline boundary recognition (without leading dashes); this header is specified only for inline snippets;\n\
* *woas.page.disposition.filename* - filename used for external page content, not ECMA-escaped; defined only with external pages;\n\
* *woas.page.mime* - mime type of external pages which have a defined mime type, like images for example;\n\
\n\
All headers are mandatory (under their specific state definition branch), except /last_modified/ and /original_length/.\n\
= Encoding\n\
The *woas.page.encoding* header can contain one of the following values:\n\
\n\
* *8bit/plain* - data is ASCII text which can use 8bits to represent characters; only ASCII text should be used and not UTF-8;\n\
* *ecma/plain* - data is ECMA-escaped UTF-8 text;\n\
* *8bit/base64* - data is base64-encoded binary data;\n\
* *text/wsif* - data is WSIF (currently used only for external WSIF pages)\n\
\n\
Pages or header values are encoded in *ecma/plain* format when UTF-8 sequences are found inside the value string, otherwise *8bit/plain* is used; *8bit/base64* is instead used for binary files or encrypted pages.\n\
= Usage notes\n\
WSIF format is pretty straightforward to produce or interpret, however please consider the following facts:\n\
\n\
* *woas.page.disposition.filename* must be plain ASCII (this limitation might be removed in future versions of the format) and should be a relative filename;\n\
* it is safe to embed a WSIF file inside another, given that boundaries are properly implemented\n\
\n\
WoaS project offers an official PHP library (libwsif) for reading/writing WSIF files, as well as a documented example.\n\
',
'\x3Cdiv\x3E\x3Cinput id="btn_import" class="woas_button_top" type="button" value="Import WSIF" onclick="woas.import_wiki_wsif()" /\x3E\x3C/div\x3E\n\
=Import content in [[WoaS::Help::WSIF|WSIF]] format.\n\
\x3Cfieldset id="S2213" class="woas_input_wrap"\x3E\x3Clegend\x3ESource\x3C/legend\x3E\\\n\
\x3Clabel class="woas_input_wrap_left"\x3EFile: \x3Cinput class="woas_input_wrap_inline" id="filename_" type="file" /\x3E\x3C/label\x3E\\\n\
\x3C/fieldset\x3E\\\n\
[[Include::WoaS::ImportSettings]]\\\n\
\x3Cscript type="text/javascript"\x3E\n\
woas.ui._import_load(true);\n\
\x3C/script\x3E\n\
',
'Wiki on a Stick (version 0.10.7 and above) supports wiki macros for pluggable wiki syntax.\n\
== Using a defined macro\n\
A macro block is enclosed in triple angle brackets. This example will create an info box using one of the built-in default macros, /woas.note/:\n\
{{{\n\
\x3C\x3C\x3Cwoas.note: *This* is /my/ note\x3E\x3E\x3E\n\
}}}\n\
This could also have been written like this:\n\
{{{\n\
\x3C\x3C\x3Cwoas.note:\n\
*This* is /my/ note\n\
\x3E\x3E\x3E\n\
}}}\n\
with exactly the same results. And here it is in action:\n\
\x3C\x3C\x3Cwoas.note:\n\
*This* is /my/ note\n\
\x3E\x3E\x3E\n\
== Default macros\n\
These macros are currently defined by WoaS:\n\
* /woas.include/ - allows a template page to be [[WoaS::Help::Template transclusion|transcluded]] with each new line of text in the macro block forming a transclusion parameter; this allows parameters to be used that would not be possible within a simple link;\n\
* /woas.note/ - as demonstrated above.\n\
== Defining a macro\n\
A macro is defined by using the special \'%\' sign before the macro name. Macro code is passed the macro object which has four standard properties:\n\
* *block* - set to true when the macro doesn\'t want any newline following it turned into a {{{\x3Cbr /\x3E}}} tag (default false);\n\
* *parse* - a simple parser function that can be used to parse text before returning it to the parser (e.g. {{{macro.text = macro.parse(macro.text)}}}), instead of using {{{reprocess = true}}}; this may speed up results in certain circumstances as it does not look for [[WoaS::Help::Include wiki page|transclude links]] ({{{[[Include::...]]}}}) or macros, and can make certain advanced macros possible (e.g. creating block markup, like headings, inside a list or table);\n\
* *reprocess* - set to true when the returned text should be re-processed by the parser (default false);\n\
* *text* - the content of the macro block after the colon. Exactly what text is passed to the macro follows some simple rules:\n\
** if there is a newline character before the actual text then it and any other whitespace before the newline will be removed;\n\
** a single whitespace character between the colon and the text will be removed;\n\
** if the closing macro block brackets are on a line by themselves then the last newline character will also be removed from the text block;\n\
** the above rules can help readability and make the macro block act in a manner consistent with the [[WoaS::Help::Nowiki text#Multi-line blocks|nowiki multi-line]] syntax.\n\
Existing macros cannot be replaced by a new macro definition. The macro should return a value of {{{true}}} to show that it completed successfully; the parser will highlight the text of a macro that returns {{{false}}}, and the debug log will include a warning if no value was returned.\n\
\n\
Let\'s define the /sum/ macro:\n\
{{{\n\
\x3C\x3C\x3C%my_sum:\n\
  var elements = macro.text.split(/[\\s\\n]+/), total = 0;\n\
  for (var i=0,l=elements.length;i\x3Cl;++i) {\n\
    if (!elements[i].length) continue;\n\
    try { total += parseInt(elements[i]); } catch(e) { }\n\
  }\n\
  macro.text = total.toString();\n\
  return true;\n\
\x3E\x3E\x3E\n\
}}}\n\
\x3C\x3C\x3C%my_sum:\n\
  var elements = macro.text.split(/[\\s\\n]+/), total = 0;\n\
  for (var i=0,l=elements.length;i\x3Cl;++i) {\n\
    if (!elements[i].length) continue;\n\
    try { total += parseInt(elements[i]); } catch(e) { }\n\
  }\n\
  macro.text = total.toString();\n\
  return true;\n\
\x3E\x3E\x3E\n\
Now we call the macro:\n\
{{{\n\
\x3C\x3C\x3Cmy_sum:\n\
24\n\
56\n\
89\n\
28\n\
19\n\
33\n\
\x3E\x3E\x3E\n\
}}}\n\
And this is the result: \x3C\x3C\x3Cmy_sum:\n\
24\n\
56\n\
89\n\
28\n\
19\n\
33\n\
\x3E\x3E\x3E\n\
== Macros with arguments\n\
Starting with WoaS 0.12.0 macros support named arguments and should return a true/false value to tell about their success/failure at rendering the macro text.\n\
\n\
Example:\n\
{{{\n\
\x3C\x3C\x3C%my_arg_macro(name, color):\n\
    macro.text = "\x3Cstrong\x3E" + name +\n\
	    "\x3C/strong\x3E says: \x3Cspan style=\\"color: " +\n\
	    color + "\\"\x3E" + macro.text + "\x3C/span\x3E";\n\
    return true;\n\
\x3E\x3E\x3E\n\
}}}\n\
\x3C\x3C\x3C%my_arg_macro(name, color):\n\
macro.text = "\x3Cstrong\x3E"+name+"\x3C/strong\x3E says: \x3Cspan style=\\"color: "+color+"\\"\x3E"+macro.text+"\x3C/span\x3E";\n\
return true;\n\
\x3E\x3E\x3E\n\
Which is then called with:\n\
{{{\n\
\x3C\x3C\x3Cmy_arg_macro("Simon", "green"):\n\
I have 3 pieces of fruit in my basket\n\
\x3E\x3E\x3E\n\
}}}\n\
And the result is:\n\
\n\
\x3C\x3C\x3Cmy_arg_macro("Simon", "green"):\n\
I have 3 pieces of fruit in my basket\n\
\x3E\x3E\x3E\n\
\n\
The passed arguments must be valid Javascript expressions.\n\
== Global macros\n\
Macros can be available on all pages if they are registered by plugins.\n\
\n\
In order to define a global macro you should create or edit a [[WoaS::Help::Plugins|plugin]] and then add Javascript code similar to this:\n\
{{{\n\
woas.macro.register(\'my.arg_macro\', function(macro, name, color) {\n\
macro.text = "\x3Cstrong\x3E"+name+"\x3C/strong\x3E says: \x3Cspan style=\\"color: " +\n\
    color + "\\"\x3E" + macro.text + "\x3C/span\x3E";\n\
return true;\n\
});\n\
}}}\n\
\x3C\x3C\x3C%my.argMacro(name, color):\n\
macro.text = "\x3Cstrong\x3E"+name+"\x3C/strong\x3E says: \x3Cspan style=\\"color: "+color+"\\"\x3E"+macro.text+"\x3C/span\x3E";\n\
return true;\n\
\x3E\x3E\x3E\n\
\x3C\x3C\x3Cwoas.note: The first parameter to the macro function is the /macro/ object that will be passed in by the parser: it doesn\'t appear in the macro call itself; it can, of course, have any name you want.\x3E\x3E\x3E\n\
If the above macro was included in a page as {{{\x3C\x3C\x3Cmy.argMacro("Paul", "red"): Hi!\x3E\x3E\x3E}}} the result would be:\n\
\n\
\x3C\x3C\x3Cmy.argMacro("Paul", "red"): Hi!\x3E\x3E\x3E\n\
\n\
You can learn more about macros by studying the macros and plugins that come with WoaS.',
'The first time you save a change to Wiki on a Stick, your browser will ask for permission to save data to the disk. This is normal and necessary for the wiki to make changes to itself. You can give permission each time or make the setting permanent.\n\
\n\
You will find the *Help* icon in the navigation bar on every page in this wiki. When you click on it, it will either open this page or a specific help page that explains how to work with the page you currently have open.\n\
\n\
When browsing the pages in this Help pop-up, you will find an *Index* button in the upper left corner that takes you back to this page, a *Back* button in the upper right corner that takes you back one page if you\'ve visited more than one page, or a *Close* button in the upper right corner that closes the pop-up.\n\
== Contents\n\
* *Features*\n\
** [[WoaS::Help::Plugins|Plugins]]\n\
** [[WoaS::Help::Security|Security]]\n\
** [[WoaS::Help::WSIF|WSIF]]\n\
* *Interface*\n\
** [[WoaS::Help::Aliases|Aliases]]\n\
** [[WoaS::Help::CSS|CSS]]\n\
** [[WoaS::Help::Edit the menu|Edit the menu]]\n\
** [[WoaS::Help::Editor|Editor]]\n\
** [[WoaS::Help::Export|Export]]\n\
** [[WoaS::Help::General usage|General usage]]\n\
** [[WoaS::Help::Go to a page|Go to]]\n\
** [[WoaS::Help::Hotkeys|Hotkeys]]\n\
** [[WoaS::Help::Import|Import]]\n\
** [[WoaS::Help::Menu|Menu]]\n\
** [[WoaS::Help::Requirements|Requirements]]\n\
* *Online use*\n\
** [[WoaS::Help::Publish wiki online|Publish wiki online]]\n\
** [[WoaS::Help::Run wiki on a web server|Run wiki on a web server]]\n\
* *Page management*\n\
** [[WoaS::Help::Create a page|Create a page]]\n\
** [[WoaS::Help::Delete a page|Delete a page]]\n\
** [[WoaS::Help::Duplicate a page|Duplicate a page]]\n\
** [[WoaS::Help::Edit a page|Edit a page]]\n\
** [[WoaS::Help::Erase all pages|Erase all pages]]\n\
** [[WoaS::Help::Namespaces|Namespaces]]\n\
** [[WoaS::Help::Page scrolling|Page scrolling]]\n\
** [[WoaS::Help::Rename a page|Rename a page]]\n\
* *Specific Help pages*\n\
** [[WoaS::Help::CSS::Boot|CSS::Boot]]\n\
** [[WoaS::Help::CSS::Core|CSS::Core]]\n\
** [[WoaS::Help::CSS::Custom|CSS::Custom]]\n\
** [[WoaS::Help::Locked|Locked]]\n\
** [[WoaS::Help::Special::Advanced|Special::Advanced]]\n\
** [[WoaS::Help::Special::All Pages|Special::All Pages]]\n\
** [[WoaS::Help::Special::Backlinks|Special::Backlinks]]\n\
** [[WoaS::Help::Special::Dead Pages|Special::Dead Pages]]\n\
** [[WoaS::Help::Special::Erase Wiki|Special::Erase Wiki]]\n\
** [[WoaS::Help::Special::Export|Special::Export]]\n\
** [[WoaS::Help::Special::ExportWSIF|Special::ExportWSIF]]\n\
** [[WoaS::Help::Special::Import|Special::Import]]\n\
** [[WoaS::Help::Special::ImportWSIF|Special::ImportWSIF]]\n\
** [[WoaS::Help::Special::Options|Special::Options]]\n\
** [[WoaS::Help::Special::Orphaned Pages|Special::Orphaned Pages]]\n\
** [[WoaS::Help::Special::Recent Changes|Special::Recent Changes]]\n\
** [[WoaS::Help::Special::Search|Special::Search]]\n\
** [[WoaS::Help::Tagged|Tagged]]\n\
** [[WoaS::Help::Unlocked|Unlocked]]\n\
** [[WoaS::Help::Untagged|Untagged]]\n\
[[Include::WoaS::Help::Syntax]]\n\
* *Troubleshooting*\n\
** [[WoaS::Help::Wiki is read-only|Wiki is read-only]]\n\
',
'* *Syntax*\n\
** [[WoaS::Help::Deprecated syntax|Deprecated syntax]]\n\
** [[WoaS::Help::Headings|Headings]]\n\
** [[WoaS::Help::Images|Images]]\n\
** [[WoaS::Help::Include text file|Include text file]]\n\
** [[WoaS::Help::Include web page|Include web page]]\n\
** [[WoaS::Help::Include wiki page|Include wiki page (transclusion)]]\n\
** [[WoaS::Help::Javascript|Javascript]]\n\
** [[WoaS::Help::Join lines of text|Join lines of text]]\n\
** [[WoaS::Help::Links|Links]]\n\
** [[WoaS::Help::Lists|Lists]]\n\
** [[WoaS::Help::Macros|Macros]]\n\
** [[WoaS::Help::Nowiki text|Nowiki text]]\n\
** [[WoaS::Help::Rulers|Rulers]]\n\
** [[WoaS::Help::Table of Contents|Table of Contents]]\n\
** [[WoaS::Help::Tables|Tables]]\n\
** [[WoaS::Help::Tags|Tags]]\n\
** [[WoaS::Help::Template transclusion|Template transclusion]]\n\
** [[WoaS::Help::Text formatting|Text formatting]]',
'The Advanced page offers some tools for administration of your wiki. The Special links lead to pages that have individual help available, except for the dynamic commands that create a prompt. Below are links to relevant help pages for those /Special::/ commands.\n\
* *Special::Delete Page* - See [[WoaS::Help::Delete a page|Delete a page]]\n\
* *Special::Duplicate Page* - See [[WoaS::Help::Duplicate a page|Duplicate a page]]\n\
* *Special::Erase Wiki* - See [[WoaS::Help::Special::Erase Wiki|Erase Wiki]]\n\
* *Special::Go to* - See [[WoaS::Help::Go to a page|Go to a page]]\n\
* *Special::New Page* - See [[WoaS::Help::Create a page|Create a page]]\n\
',
'The *Special::Erase Wiki* link on the [[Special::Advanced]] page allows you to erase all user-created pages and the original /Main Page/ if it still exists, and all content from the menu. The new file will contain default /Main Page/ and /::Menu/ pages. Global core CSS settings will be preserved, but the [[WoaS::CSS::Custom]], Alias, and Hotkey pages will be reset to default values.\n\
\n\
If you have not given permanent permission to your browser for editing wiki pages, you will receive a security warning when attempting to erase the wiki. If you deny permission to the browser, you will receive a message that saving the file failed. The orginal wiki should then be automatically reloaded from the file..\n\
',
'The look and feel of WoaS can be customized by specifying custom CSS in the [[WoaS::CSS::Custom]] reserved page. You can use WoaS core CSS definitions available in [[WoaS::CSS::Core]] as a reference when you are writing CSS customization.\n\
\n\
\x3C\x3C\x3Cwoas.note: A tutorial about CSS is available at [[http://www.w3schools.com/css/]].\x3E\x3E\x3E\n\
== Customizing CSS\n\
# Access [[WoaS::CSS::Core]] either directly or from [[Special::Advanced]]\n\
# Copy the CSS definitions you want to customize\n\
# Access [[WoaS::CSS::Custom]] either directly or from [[Special::Advanced]]\n\
# Edit the page and paste the classes and ids you copied in previous step\n\
# Define the rules for the CSS classes and ids.\n\
# Save your changes by clicking the *Save* icon in the navigation bar.\n\
\n\
All changes will be visible immediately.\n\
== Restore the default CSS settings\n\
You can always restore WoaS default CSS by deleting the content of [[WoaS::CSS::Custom]].\n\
== Import CSS rules into your wiki\n\
You can import the CSS rules from another copy of WoaS by following the instructions for [[WoaS::Help::Import|importing]] another wiki into the current one and placing a check in the box next to *Import custom CSS.*\n\
\n\
Importing from older versions of WoaS can garble the layout of the wiki. There are two ways to avoid this:\n\
# Manually transfer the CSS from the older version of WoaS into the [[WoaS::CSS::Custom]] page by copying and pasting it, checking the class and id of each entry against the default CSS rules on the [[WoaS::CSS::Core]] page to verify that it\'s still in use before saving your changes.\n\
# Create a new page with style tags in it and paste your CSS into that page to test it before adding it to the [[WoaS::CSS::Custom]] page.\n\
=== Create a test page for your custom CSS\n\
# Access [[Special::Options]] either directly or from [[Special::Advanced]]\n\
# Make sure that the box is /not/ checked next to *Remember current page and navigation history*. Save the change if you had to uncheck the box.\n\
# Create a [[Special::New Page|new page]]\n\
# Insert this opening tag at the top of the page:\x3Cbr/\x3E{{{\n\
\x3Cstyle type="text/CSS"\x3E\n\
}}}\n\
# Paste your CSS rules beneath the tag.\n\
# Insert this closing tag at the bottom of the page:\x3Cbr/\x3E{{{\n\
\x3C/style\x3E\n\
}}}\n\
# Save changes\n\
\n\
Once you have tested your CSS on a single page you can choose whether to move such CSS definitions to [[WoaS::CSS::Custom]] or not.\n\
',
'This page displays a list of pages that contain links to nonexistent pages. Both the link and the page it\'s on are shown in each entry.\n\
\n\
Fixing dead pages is a good way to not break end-user browsing experience.\n\
',
'== Cancel any action\n\
Cancel any action by clicking the *Cancel* icon in the navigation bar, clicking the *Cancel* button on any alert that pops up, or pressing the *Esc* key.\n\
== Navigation\n\
Use the *Back* and *Forward* arrow icons in the navigation bar to go back or forward one page, the *Main Page* icon in the navigation bar to return to the {{{[[Main page]]}}}, or click the buttons and links in the menu and wiki pages.\n\
== Pages linking to the current page\n\
Click the *Backlinks* link in the menu to see which pages link to the page you currently have open.\n\
== Print a page\n\
Click the *Print* icon in the navigation bar. A new browser window will open with a printer-friendly version of the main text area. Use the browser\'s print functions to print the page.\n\
== Syntax\n\
This wiki accepts plain text, WoaS wiki syntax, and XHTML. See the *Syntax* section of the [[WoaS::Help::Index|Help index]] by clicking the *Help* icon in the navigation bar for help with using the syntax in your pages.\n\
\x3C\x3C\x3Cwoas.note: WoaS syntax is partially compatible with Creole 0.1 syntax.\x3E\x3E\x3E',
'/Nowiki text/ is a section of raw or preformatted text that is not parsed as wiki syntax. Anything you place inside nowiki brackets will be displayed in monospace font exactly as you typed it.\n\
== Multi-line blocks\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E{\\\n\
{{\n\
This is a code block\n\
made of one\n\
or more lines.\n\
}}\\\n\
}\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
{{{\n\
This is a code block\n\
made of one\n\
or more lines.}}}\n\
== Inline nowiki blocks\n\
A normal sentence can contain an inline nowiki block, like {{\x3C!-- --\x3E{this block}}\x3C!-- --\x3E}.\n\
\n\
Example (with the mathematical equation inside a nowiki block):\n\
\n\
The equation {{{E = mc^2}}} indicates that energy always exhibits mass in whatever form the energy takes.\n\
== Nowiki blocks inside lists\n\
A nowiki block can be added to a list item by inserting the opening curly brackets at the end of the list item.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E* List item:&#123;&#123;&#123;\n\
This is a code block\n\
made of one\n\
or more lines.\n\
&#125;&#125;&#125;\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
* List item:{{{\n\
This is a code block\n\
made of one\n\
or more lines.\n\
}}}\n\
\n\
To insert a newline between the list item and the nowiki block, you can use HTML {{{\x3Cbr\x3E}}} tags before the opening curly brackets.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E* List item:&lt:br&gt;&lt;br&gt;&#123;&#123;&#123;\n\
This is a code block\n\
made of one\n\
or more lines.\n\
&#125;&#125;&#125;\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
* List item:\x3Cbr\x3E\x3Cbr\x3E{{{\n\
This is a code block\n\
made of one\n\
or more lines.\n\
}}}\n\
== Nowiki block with custom CSS style\n\
The example uses /lightcyan/ and /purple/ colors, but you can replace those with whatever colors you like, using [[http://www.w3schools.com/Html/html_colornames.asp|color names or hexadecimal notation]].\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cdiv class="woas_help_code"\x3E\n\
&lt;span style="background-color:lightcyan; color:purple;"&gt;&#123;&#123;&#123;\n\
This is a code block\n\
made of one\n\
or more lines.\n\
&#125;&#125;&#125;&lt;/span&gt;\n\
\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cspan style="background-color:lightcyan; color:purple;"\x3E{{{\n\
This is a code block\n\
made of one\n\
or more lines.\n\
}}}\x3C/span\x3E\n\
',
'\x3Cdiv style="background-color: #FFFFAA; border: 0.1em solid; padding: 0.2em;"\x3E\x3Cimg src="" alt="Info" border="0" /\x3E %1\x3C/div\x3E\n\
\x3Cscript\x3E\n\
woas.log("DEPRECATED: WoaS::Template::Info. Use the much more flexible woas.note macro instead; e.g.:\\n     \x3C"+"\x3C\x3Cwoas.note: My note text\x3E"+"\x3E\x3E");\n\
\x3C/script\x3E',
'Read-only protection is by no means a security mechanism (see [[WoaS::Help::Security|Security]]), but rather an invitation to /fair use/ of the content. The author disables the write features assuming they won\'t be useful to the end-user or to indicate their expectation that the content won\'t be edited or copied.\n\
\n\
To re-enable the write features manually:\n\
# Back up your WoaS\n\
# Open it in a text editor\n\
# Do a search for: {{{"permit_edits":false,}}}\n\
# Replace it with: {{{"permit_edits":true,}}}\n\
# Save the file\n\
\n\
*NOTE:* this way of re-enabling WoaS write mode is *unsupported*, i.e. it might not work in future versions of WoaS.\n\
',
'# Access [[Special::New Page]]\n\
# Type the page title. Maximum length is 256 characters, although you might want to use a shorter title to not interfere with the navigation bar. Page titles are case sensitive, all characters are allowed except angled brackets, square brackets, curly braces, and pipe, hash, or double-quote characters ({{{\x3C\x3E[]{}|#"}}})\n\
# Press the *Enter* key or click the *OK* button\n\
# When asked if you\'d like to add a link into the main menu, accept by pressing the *Enter* key or clicking the *OK* button, or refuse by pressing the Escape key or clicking the *Cancel* button\n\
# Edit the contents of the main text area by typing normally. You can freely change the default text (a level one heading with the page name)\n\
# Use the editor\'s buttons to insert wiki syntax to format the text or type the wiki syntax manually (plain text does not need any wiki syntax)\n\
# Save your changes\n\
== Create a missing page\n\
An alternate method of creating a page is to type a new page title inside square brackets and then attempt to access the unexisting page.\n\
\n\
*Example:*\n\
{{{\n\
[[My new page]]\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EIs rendered as:\x3C/div\x3E\n\
[[My new page]]\n\
= Troubleshooting\n\
There are some issues which could prevent you from creating a page.\n\
\n\
* You didn\'t type a title for the page in the input box that popped up\n\
* There is already a page by that title\n\
* The wiki is being run in [[WoaS::Help::Publish wiki online|read-only mode]], so no changes are allowed. See the [[WoaS::Help::Wiki is read-only|Wiki is read-only]] page for instructions on how to return the wiki to editing mode\n\
* You are trying to use a [[WoaS::Help::Namespaces|namespace]] that is reserved by WoaS. In this case a message will pop up letting you know the namespace is reserved and giving you an opportunity to choose a different title/namespace for the page\n\
',
'= By /Special::Delete Page/ action link/command\n\
# Access [[Special::Delete Page]] from a [[WoaS::Help::Links|link]] (e.g. from the Special::[[WoaS::Help::Special::Advanced|Advanced]] page, default [[WoaS::Help::Menu|menu]], or user page) or by using the Special::[[WoaS::Help::Go to a page|Go to]] command.\n\
# You\'ll be asked for the exact title of the page and then for confirmation\n\
# When the page is deleted, you\'ll be returned to the page you were on before deleting the page.\n\
= By editing\n\
# [[WoaS::Help::Edit a page|Edit]] the page you wish to delete\n\
# Select everything inside the main text area and delete it\n\
# You will be asked to confirm the deletion when you Save the page\n\
= References to deleted pages\n\
Access [[Special::Dead Pages]] either directly or from [[Special::Advanced]] to remove references to the deleted page.\n\
',
'* Cancel all changes by clicking the *Cancel* icon in the navigation bar at any time.\n\
* Change the title of a page by editing the contents of the *Page title* box.\n\
* Save all changes by clicking the *Save* icon in the navigation bar at any time.\n\
* See examples of how tables are built by clicking the *Tables* link.\n\
* Toggle the display of the button rows by clicking the *Wiki | XHTML* links.\n\
== Wiki buttons\n\
Buttons to ease printing [[WoaS::Help::Syntax|wiki syntax]].\n\
{|\n\
|+ Wiki Code buttons\n\
| *Button* || *What it does*\n\
| Wiki URL || Add a wiki link to a page.\n\
| URL || Add an external link to a page.\n\
| {{{=}}} || Insert wiki syntax for a level one heading. Use this at the beginning of any line.\n\
| {{{==}}} || Insert wiki syntax for a level two heading. Use this at the beginning of any line.\n\
| Img || Include a wiki image in the page.\n\
| *B* || Wrap selected text with bold syntax.\n\
| /i/ || Wrap italic text with bold syntax.\n\
| u || Wrap selected text with underline syntax.\n\
| &#123;&#123;&#123; &#125;&#125;&#125; || Wrap wiki syntax around the selected text to make it nowiki (raw) text.\n\
| * || Insert the wiki syntax for a bulleted list item.\n\
| # || Insert the wiki syntax for a numbered list item.\n\
| @ || Insert the wiki syntax for an alphanumeric list item.\n\
| Ruler || Insert a ruler (horizontal line). Use this at the beginning of any line.\n\
| Tags || Interface for inserting tags in your page to categorize it. Use a comma between multiple tags.\n\
|}\n\
\n\
*Note:* it\'s recommended to use [[WoaS::Help::Syntax|wiki syntax]] instead of XHTML syntax, because this is a wiki.\n\
== XHTML buttons\n\
{|\n\
|+ XHTML Code buttons\n\
| *Button* || *What it does*\n\
| *B* || Wrap selected text with bold tags.\n\
| /i/ || Wrap selected text with emphasis tags (italics).\n\
| u || Wrap selected text with underline tags.\n\
| s || Wrap selected text with strike-through tags.\n\
| Sup || Wrap selected text with superscript tags (appearing half a character above the baseline).\n\
| Sub || Wrap selected text with subscript tags (appearing half a character below the baseline).\n\
| Left || Wrap selected text with a left-aligned div.\n\
| Center || Wrap selected text with a center-aligned div.\n\
| Right || Wrap selected text with a right-aligned div.\n\
| Justify || Wrap selected text with a justified div.\n\
| List || Add unordered list tags around the selected text.\n\
| List = || Add ordered list tags around the selected text.\n\
| li[*] || Wrap selected text with list item tags.\n\
| Blockquote || Wrap selected text with blockquote tags, indenting it beneath the current line.\n\
| Image || Include an external image.\n\
| Link || Include an external link URL.\n\
|}\n\
',
'All user-created pages (and some which are part of reserved [[WoaS::Help::Namespaces|namespaces]]) can be edited.\n\
\n\
If a page is editable the /Edit/ icon will be available in the navigation bar; you start editing the page by clicking such icon. The user interface will switch to an [[WoaS::Help::Editor|editor-mode set of buttons and edit areas]].\n\
== Editing\n\
In order to edit pages, click the *Edit* icon in the navigation bar. You can find all the user pages by accessing [[Special::All Pages]] directly or either from [[Special::Advanced]].\n\
# Click the *Edit* icon in the navigation bar or double-click on the page if you\'ve enabled that setting in the wiki Options.\x3Cbr\x3E\x3Cbr\x3E\n\
# Edit the contents of the main text area by typing normally.\x3Cbr\x3E\x3Cbr\x3E\n\
# Use the editor\'s buttons to insert code to format the text, or type the code in manually. Note that the use of plain text doesn\'t require any code.\x3Cbr\x3E\x3Cbr\x3E\n\
# Save your changes by clicking on the *Save* icon in the navigation bar.\n\
== Deleting\n\
See [[WoaS::Help::Delete a page|Delete a page]].\n\
',
'To erase all user-created pages in this wiki and start fresh:\n\
# Access [[Special::Erase Wiki]] directly or either from [[Special::Advanced]]\n\
\x3C\x3C\x3Cwoas.note: Make sure you are using a wiki you don\'t mind losing. If not, make a copy and erase the copy.\x3E\x3E\x3E\n\
See also the [[WoaS::Help::Special::Erase Wiki|Erase Wiki]] page.\n\
',
'# Click the /Edit menu/ button at the bottom of the menu\n\
# Edit the contents of the main text area; the menu page is like a normal wiki page\n\
# Save your changes by clicking on the *Save* icon in the top right navigation panel\n\
\n\
You can use various styles for your menu. A detailed explanation of list styles can be found on the [[WoaS::Help::Lists|Lists]] page.\n\
== Using sub-menus\n\
See the [[WoaS::Help::Namespaces#Namespace sub-menu|Namespace sub-menu]] section of the [[WoaS::Help::Namespaces|Namespaces]] page.\n\
',
'Below are examples on how to use wiki markup to create headings in this wiki. There are six levels of supported headings.\n\
\n\
{{{\n\
= Heading level 1\n\
}}}\n\
= Heading level 1\n\
{{{\n\
== Heading level 2\n\
}}}\n\
== Heading level 2\n\
{{{\n\
=== Heading level 3\n\
}}}\n\
=== Heading level 3\n\
{{{\n\
==== Heading level 4\n\
}}}\n\
==== Heading level 4\n\
{{{\n\
===== Heading level 5\n\
}}}\n\
===== Heading level 5\n\
{{{\n\
====== Heading level 6\n\
}}}\n\
====== Heading level 6\n\
',
'Rulers (horizontal rules or lines) use the full width of the page by default. They can be styled to a smaller width by surrounding them with HTML &lt;div&gt; tags. Styling can also control their position.\n\
== Standard ruler\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
----\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\x3Cbr\x3E\n\
----\n\
== Custom width ruler aligned left\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing 50% with the width you like:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cdiv style="width:50%";\x3E\n\
----\n\
\x3C/div\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cdiv style="width:50%";\x3E\n\
----\n\
\x3C/div\x3E\n\
== Custom width ruler aligned right\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing 50% with the width you like:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cdiv style="width:50%; float:right;"\x3E\x3Chr\x3E\x3C/div\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cdiv style="width:50%; float:right;"\x3E\x3Chr\x3E\x3C/div\x3E\n\
== Custom width centered ruler\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing 50% with the width you like:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Ccenter\x3E\x3Cdiv style="width:50%";\x3E\n\
----\n\
\x3C/div\x3E\x3C/center\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Ccenter\x3E\x3Cdiv style="width:50%";\x3E\n\
----\n\
\x3C/div\x3E\x3C/center\x3E\n\
',
'Including the contents of one wiki page inside another wiki page is called /transclusion/. To accomplish this use an {{{[[Include::]]}}} tag on a line by itself, inserting the name of the page you\'d like to transclude after the double colons in the tag.\n\
\x3C\x3C\x3Cwoas.note: Page names are case sensitive.\x3E\x3E\x3E\n\
\x3Cspan class="woas_help_text"\x3EUse this code in a page, replacing Page Name with the name of the page you wish to include:\x3C/span\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::Page Name]]\x3C/div\x3E\n\
\x3Cspan class="woas_help_text"\x3ETo include the contents of another wiki page in the current page.\x3C/span\x3E\n\
== Example\n\
\x3Cspan class="woas_help_text"\x3EUse this code in a page:\x3C/span\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::WoaS::Aliases]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cspan class="woas_help_text"\x3ETo create this (the [[WoaS::Aliases]] page):\x3C/span\x3E\n\
\n\
[[Include::WoaS::Aliases]]\n\
== Template transclusion\n\
WoaS can also transclude template pages, allowing you to change the content of a transcluded page by using link parameters; see [[WoaS::Help::Template transclusion|Template transclusion]].\n\
',
'== Adding Javascript to the wiki source\n\
You can add &lt;script&gt; tags to your wiki source and they will be correctly rendered in the document &lt;head&gt; tag each time the page is loaded; external scripts (using the /src/ attribute) will also be parsed and activated. The order of declaration of the &lt;script&gt; tags will be respected.\n\
\x3C\x3C\x3Cwoas.note: Since the Javascript tags are activated from within the &lt;head&gt; tag, you cannot use document.write() or similar inline Javascript statements.\x3E\x3E\x3E\n\
It is very often better to use a [[WoaS::Help::Macros|macro]] or other Javascript loaded by a custom [[WoaS::Help::Plugins|plugin]]. The code or macro is then loaded once when the file is first loaded and is available to all your pages.\n\
=== Adding Javascript to your page\n\
To add Javascript to your page, you must enclose it inside script tags.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing YOUR_CODE_HERE with your Javascript code:\x3C/div\x3E\n\
{{{\n\
\x3Cscript type="text/javascript"\x3E\n\
YOUR_CODE_HERE\n\
\x3C/script\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3ETo add Javascript to your page.\x3C/div\x3E\n\
=== Using external Javascript\n\
You can include external Javascript on a page by placing the script file in the same directory as the WoaS file and then inserting a reference to it in the body of the page.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing SCRIPTNAME.JS with the name of your script:\x3C/div\x3E\n\
{{{\n\
\x3Cscript src="SCRIPTNAME.JS" type="text/javascript"\x3E\x3C/script\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3ETo include an external Javascript in a page.\x3C/div\x3E\n\
== Using the /Javascript::/ namespace in a link\n\
Using a Javascript expression contained in a link, WoaS can dynamically create a temporary page that only exists while it is being displayed and is not stored as a page in the wiki. It does this through the /Javascript::/ namespace. Everything following the namespace declaration will be evaluated as a Javascript expression. You can use /$JS::/ instead of /Javascript::/ if your [[WoaS::Help::Aliases|Aliases]] page still contains the default {{{$JS  Javascript}}} declaration.\n\
\x3C\x3C\x3Cwoas.note: /Javascript::/ links cannot be [[WoaS::Help::Include wiki page|transcluded]], cannot contain double-quotes ({{{"}}}), and do not create history (back/forward entries).\x3E\x3E\x3E\n\
If the Javascript expression returns a non-empty string it will be used as the body of the dynamic page and the link text will be used as the title of the page. If the expression returns an array and that array contains exactly two strings, then the first string will be used as the dynamic page\'s title (with /Javascript::/ added), and the second one will form the content of the page. Any other return types will be ignored, as will an empty content string. The content string can be WoaS wiki syntax, HTML, or a combination of both; it is parsed just as a normal page is.\n\
\n\
A simple (but useless) example is:\n\
{{{\n\
[[Javascript::\'=Hi\']]\n\
}}}\n\
This link should create a dynamic page in the main wiki: [[Javascript::\'=hi\']]. Note that the Javascript expression is used as the page title; usually not very useful! Another simple example (and equally useless, except we don\'t have the title this time; note the need for a space after the array\'s closing bracket):\n\
{{{\n\
[[Javascript::[\'\',\'=Hi\'] ]]\n\
}}}\n\
And here\'s the link: [[Javascript::[\'\',\'=Hi\'] ]]. The space isn\'t needed if, as is usual, you are using a label after the page link; for example:\n\
{{{\n\
[[Javascript::[\'\',\'Hello World\']|A dynamic page]]\n\
}}}\n\
These links should open in the main wiki window; the first uses /Javascript::/ in the page source, the second /$JS::/ (though you won\'t see this when hovering over the link if your /$JS/ Alias is set): [[Javascript::[\'\',\'Hello World\']|A dynamic page]], [[$JS::[\'\',\'Hello World\']|A dynamic page]].\n\
\n\
These simple examples could even contain a [[WoaS::Help::Links|link]] (note the use of {{{]\\]}}} in the link):\n\
{{{\n\
[[Javascript::[\'Hello world\',\'I am Hello World, not the [[Special::All Pages]\\] page\']|A pointless page]]\n\
}}}\n\
The above example as a [[Javascript::[\'Hello world\',\'I am Hello World, not the [[Special::All Pages]\\] page\']|pointless page link]].\n\
\n\
Here is a slightly more useful example that uses a Javascript function:\n\
{{{\n\
\x3Cscript type="text/javascript"\x3E\n\
  function rhyme1() {\n\
    return [\'A Rhyme\',\n\
      \'=Hello Lamppost\\nWhat cha knowing?\\n\' +\n\
      \'I\\\'ve come to watch\\n* your flowers\\n* growing.\'];\n\
  }\n\
\x3C/script\x3E\n\
}}}\n\
\x3Cscript type="text/javascript"\x3E\n\
	function rhyme1() {\n\
		return [\'A Rhyme\',\'=Hello Lamppost\\nWhat cha knowing?\\n\' +\n\
		\'I\\\'ve come to watch\\n* your flowers\\n* growing.\'];\n\
	}\n\
\x3C/script\x3E\n\
The link {{{[[Javascript::rhyme1()|Rhymes]]}}} will open this page in the main wiki window: [[Javascript::rhyme1()|Rhymes]]\n\
\n\
The Javascript function can also be passed dynamic content using one or more function parameters:\n\
{{{\n\
\x3Cscript type="text/javascript"\x3E\n\
  function rhyme2(thing) {\n\
    return [\'A \'+thing+\' Rhyme\',\'=Hello \'+thing+\n\
      \'\\nWhat cha knowing?\\n\' +\n\
      \'I\\\'ve come to watch\\n* your flowers\\n* growing.\'];\n\
  }\n\
\x3C/script\x3E\n\
}}}\n\
\x3Cscript type="text/javascript"\x3E\n\
	function rhyme2(thing) {\n\
		return [\'A \'+thing+\' Rhyme\',\'=Hello \'+thing+\n\
		  \'\\nWhat cha knowing?\\n\' +\n\
		  \'I\\\'ve come to watch\\n* your flowers\\n* growing.\'];\n\
	}\n\
\x3C/script\x3E\n\
The link {{{[[Javascript::rhyme2(\'Lamppost\')|Rhymes]]}}} will open this page in the main wiki window: [[Javascript::rhyme2(\'Lamppost\')|Rhymes]]. This one uses /$JS/: [[$JS::rhyme2(\'World\')|Another rhyme]].\n\
\n\
Not that the above example would be more easily accomplished by [[WoaS::Help::Template transclusion|transcluding]] a template page and passing in replacement parameters. Nevertheless, there are times when generating changable, dynamic text is perfectly suited to the /Javascript::/ namespace technique.\n\
',
'Lengthy wiki page content can be broken up into shorter lines in the editor (while still being parsed as a single line when the page is viewed) by using a backslash at the *end* of any line; such a line will be joined with the one below it.\n\
\x3C\x3C\x3Cwoas.note: Backslashes *within* a line will be ignored by the wiki parser and will not influence how the text is displayed.\x3E\x3E\x3E\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\n\
{{{\n\
Putting a \\ at the end of any line \\\n\
makes it join together \\\n\
with the line below it.\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
Putting a \\ at the end of any line \\\n\
makes it join together \\\n\
with the line below it.\n\
',
'When you create a page with double colons (*::*) as a separator in the page name, you are using a namespace to define parent and child pages. Sub-namespaces are created by adding more than one *::* separator to the page name. Each namespace or sub-namespace can have as many child pages under it as you like (within the resource limits of your hardware). The full path to each page is displayed in the navigation bar with links to its namespace and sub-namespace(s) in the title.\n\
\n\
For example, let\'s say you have these pages:\n\
* {{{[[Recipes::Desserts]]}}}\n\
* {{{[[Recipes::Desserts::Cakes]]}}}\n\
* {{{[[Recipes::Main dishes]]}}}\n\
* {{{[[Recipes::Side dishes]]}}}\n\
* {{{[[Recipes::Soups]]}}}\n\
\n\
*Recipes::* is a namespace. *Desserts::* is a sub-namespace of the *Recipes::* namespace. *Cakes::* is a sub-namespace of the *Desserts::* sub-namespace.\n\
\n\
If you open the {{{[[Recipes::Desserts::Cakes]]}}} page, the title in the navigation bar contains links to *Recipes* and *Desserts*. The *Recipes* link opens a page listing all pages in the *Recipes::* namespace, and the *Desserts* link opens a page listing all pages in the *Desserts::* sub-namespace.\n\
=== Namespace sub-menu\n\
All pages in any namespace can be given a custom sub-menu by creating a *::Menu* page inside the namespace. The sub-menu content will replace the [[WoaS::Help::Menu|::Menu]] content while any pages belonging to that page\'s namespace are open. The sub-menu will vanish as soon as you navigate away from its namespace.\n\
\n\
You can control what the sub-menu displays by editing the page with *::Menu* in its name, or by clicking the menu edit icon (bottom right corner of the menu) while it is being displayed. A menu is just a wiki page that is displayed in the menu area, so anything a normal page can contain a menu page can as well; this includes Javascript scripts and CSS style sheets, allowing very flexible customization of namespaces. To [[WoaS::Help::Include wiki page|include]] the main menu in a sub-menu use {{{[[Include::::Menu]]}}}.\n\
\n\
For example, if you create the {{{[[Recipes::Menu]]}}} page with *My favorite recipes!* as its content, then whenever you open a page in the {{{Recipes::}}} namespace, a sub-menu will appear with *My favorite recipes!* in it.\n\
=== Sub-namespace sub-menu\n\
All pages in any sub-namespace can be given a custom sub-menu by creating a *::Menu* page inside the sub-namespace. The sub-menu will be displayed beneath the main menu while any pages belonging to that page\'s sub-namespace are open. You can determine what goes into the sub-menu by editing the page with *::Menu* in its name. The sub-menu will vanish as soon as you navigate away from its sub-namespace.\n\
\n\
To include the main menu in a sub-menu use {{{[[Include::::Menu]]}}}. You can also include menus from lower namespaces in the same way.\n\
\n\
For example, if you create the {{{[[Recipes::Desserts::Menu]]}}} page with *My favorite desserts!* as its content, then whenever you open a page in the {{{Recipes::Desserts::}}} sub-namespace, a sub-menu will appear with *My favorite desserts!* in it.\n\
\n\
If a namespace contains namespace and sub-namespace ::Menu pages and you open a page in the sub-namespace, the contents of the sub-namespace ::Menu page will be displayed. If a sub-namespace has no menu but a lower namespace does, then that menu will be used instead.\n\
\x3C\x3C\x3Cwoas.note: Sub-menus work the same way menus do. For more information on menus see the [[WoaS::Help::Edit the menu|Edit the menu]] page.\x3E\x3E\x3E\n\
There is no limit to how many sub-namespaces you can have, other than the 256 character limit for title length.\n\
== Reserved namespaces\n\
Some namespaces are reserved by the wiki for its own internal use or for specific use by the user\n\
* *::Menu* is a special reserved namespace used for the [[WoaS::Help::Menu|menu]] and sub-menus\n\
\n\
These are listable namespaces:\n\
* *File::* for embedded files\n\
* *Image::* for embedded images\n\
* *Locked::* for listing encrypted pages\n\
* *Special::* for all the special pages\n\
* *Tagged::* for listing tagged pages\n\
* *Unlocked::* for listing plain (unencrypted) pages\n\
* *Untagged::* for listing untagged pages\n\
* *WoaS::* for core WoaS pages\n\
\n\
Some namespaces cannot be listed but are used inside wiki links to accomplish a task:\n\
* *Include::* for transclusion\n\
* *Javascript::* for direct Javascript execution\n\
* *Lock::* used internally or in a link to lock (encrypt) a page\n\
* *Tag::* syntax used to tag a page\n\
* *Tags::* alternative syntax used to tag a page\n\
* *Unlock::* used internally or in a link to unlock (decrypt) a page\n\
',
'== Bold\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
*This is bold text.*\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
*This is bold text.*\n\
== Colored\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cspan style="color:#FF00FF"\x3EThis is colored text.\x3C/span\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cspan style="color:#FF00FF"\x3EThis is colored text.\x3C/span\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EOr use this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cspan style="color:fuchsia"\x3EThis is colored text.\x3C/span\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cspan style="color:fuchsia"\x3EThis is colored text.\x3C/span\x3E\n\
== Italic\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
/This is italic text./\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
/This is italic text./\n\
== Plain\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
This is plain text.\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
This is plain text.\n\
== Underlined\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
_This is underlined text._\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
_This is underlined text._\n\
== Underlined Bold Italic\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
_*/This is underlined and bold and italic text./*_\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
_*/This is underlined and bold and italic text./*_\n\
',
'# Click the *Edit* icon in the navigation bar.\n\
# Edit the contents of the text inside the *Page title* area at the top of the page.\n\
# Save your changes by clicking on the *Save* icon in the navigation bar.\n\
= Reference links\n\
Renaming a page will automatically rename also the references to such page in other pages.\n\
',
'By default, this wiki offers two choices for scrolling. You can change these settings by clicking the *Advanced* icon in the navigation bar and then clicking the {{{[[Special::Options]]}}} link.\n\
\n\
The *Fixed menu* and *Fixed navigation bar* options can be enabled and disabled by placing a check mark in the box next to the option. Enabling them locks the navigation bar and/or the menu in place while allowing the rest of the page to scroll. Disabling them allows the entire page to scroll as one connected unit.\n\
',
'You can insert a Table of Contents into your page by using a special wiki tag. It will be automatically populated with all the headings on a page. The placement of the Table of Contents is determined by where you put the tag in the page.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code on a line by itself in a page:\x3C/div\x3E{{{\n\
[[Special::TOC]]\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3ETo add a Table of Contents to the page.\x3C/div\x3E\n\
== Example\n\
If you were to create a page with these contents:\n\
{{{\n\
[[Special::TOC]]\n\
= My level one heading\n\
== My level two heading\n\
=== My level three heading\n\
==== My level four heading\n\
===== My level five heading\n\
====== My level six heading\n\
= My next level one heading\n\
}}}\n\
the displayed page would have a Table of Contents at the top of the page similar to the following:\n\
\n\
\x3Cdiv id="woas_page"\x3E\x3Cdiv id="woas_toc"\x3E\n\
\x3Cdiv id="woas_toc_title"\x3ETable of Contents\x3C/div\x3E\n\
\x3Cdiv class="woas_toc_h1"\x3E\x3Ca class="woas_link"\x3EMy level one heading\x3C/a\x3E\x3C/div\x3E\n\
\x3Cdiv class="woas_toc_h2" style="margin: 0px 1.5em "\x3E\x3Ca class="woas_link"\x3EMy level two heading\x3C/a\x3E\x3C/div\x3E\n\
\x3Cdiv class="woas_toc_h3" style="margin-left: 3em"\x3E\x3Ca class="woas_link"\x3EMy level three heading\x3C/a\x3E\x3C/div\x3E\n\
\x3Cdiv class="woas_toc_h4" style="margin-left: 4.5em"\x3E\x3Ca class="woas_link"\x3EMy level four heading\x3C/a\x3E\x3C/div\x3E\n\
\x3Cdiv class="woas_toc_h5" style="margin-left: 6em"\x3E\x3Ca class="woas_link"\x3EMy level five heading\x3C/a\x3E\x3C/div\x3E\n\
\x3Cdiv class="woas_toc_h6" style="margin-left: 7.5em"\x3E\x3Ca class="woas_link"\x3EMy level six heading\x3C/a\x3E\x3C/div\x3E\n\
\x3Cdiv\x3E\x3Ca class="woas_link"\x3EMy next level one heading\x3C/a\x3E\x3C/div\x3E\n\
\x3C/div\x3E\x3C/div\x3E\n\
The exact look of the TOC is controlled by the current CSS and Javascript, both of which can be changed. The WoaS default implementation includes the ability to toggle the TOC display by clicking the /Table of Contents/ title text.',
'Tags are used to group pages by categories/features/topics so they can easily be found again.\n\
\n\
Tags can be placed anywhere on a page, but choosing a standard location like the bottom of the page makes them easier to find and edit as your wiki grows.\n\
\n\
Tag a page by using a {{{[[Tag::tag1]]}}} link, adding the tag name or names after the double colons; multiple tags should be separated with commas.\n\
\n\
You can also use the *Tag* button in the editor.\n\
=== Add a tag to a page (method 1)\n\
# Click the *Tags* button in the editor.\x3Cbr\x3E\x3Cbr\x3E\n\
# Type in a name for the tag.\x3Cbr\x3E\x3Cbr\x3E\n\
# Click the *OK* button.\n\
=== Add a tag to a page (method 2)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing EXAMPLE with the name of the tag you\'d like to add:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Tag::EXAMPLE]]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo add a tag to your page.\x3C/div\x3E\n\
=== Add more than one tag to a page (method 1)\n\
# Click the *Tags* button in the editor.\x3Cbr\x3E\x3Cbr\x3E\n\
# Type in names for the tags, separating each from the one before it with a comma. For example:\x3Cbr\x3E\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing EXAMPLE1, EXAMPLE2, and EXAMPLE3 with the names of the tags you\'d like to add:\x3C/div\x3E\x3Cbr\x3E\x3Cdiv class="woas_help_code"\x3E{{{[[Tag::EXAMPLE1, EXAMPLE2, EXAMPLE3]]}}}\x3C/div\x3E\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo add three tags to your page.\x3C/div\x3E\x3Cbr\x3E\n\
# Click the *OK* button.\n\
=== Add more than one tag to a page (method 2)\n\
To use more than one tag on a page, use one tag link and add as many tags as you like, separating each from the one before it with a comma. For example: {{{[[Tag::Recipes, Chocolate, Layered cakes]]}}}.\n\
=== Choosing tag names\n\
Tag names are case sensitive. For example: {{{[[Tag::Recipes]]}}} and {{{[[Tag::recipes]]}}} are two different tags.\n\
\n\
Tag names can be more than one word long with a space between each word. For example: {{{[[Tag::Layered cakes]]}}}.\n\
=== Add a link to tagged pages\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing EXAMPLE with the tag you\'d like to use:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E{{{[[Tagged::EXAMPLE]]}}}\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create a listing of pages tagged with EXAMPLE.\x3C/div\x3E\n\
=== Add a filtered link to tagged pages\n\
By putting an exclamation mark (*!*) in front of the tag name, you can filter out a specific tag from a tagged pages list:\x3Cbr\x3E\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing EXAMPLE with the tag you\'d like to filter out:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Tagged::!EXAMPLE]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create a filtered listing of tagged pages that are not tagged with EXAMPLE.\x3C/div\x3E\n\
=== Include a listing of tagged pages\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing EXAMPLE with the tag you\'d like to use:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::Tagged::EXAMPLE]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo display a listing of pages tagged with EXAMPLE inside the current page.\x3C/div\x3E\n\
=== Include a filtered listing of tagged pages\n\
By putting an exclamation mark (*!*) in front of the tag name, you can filter out a specific tag from a tagged pages list:\x3Cbr\x3E\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing EXAMPLE with the tag you\'d like to filter out:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::Tagged::!EXAMPLE]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo display a filtered listing of tagged pages that are not tagged with EXAMPLE inside the current page.\x3C/div\x3E\n\
',
'This wiki can be published online as a single-file, framed web page by making it read-only. The read-only format can also be used for sharing your work with others by email. Most email programs accept .html pages as attachments.\n\
# Make a backup copy of this wiki.\n\
# Click the *Advanced* icon in the navigation bar.\n\
# Scroll to the bottom of the page.\n\
# Click the *Disallow edits* button to make the file read-only.\n\
# Upload the wiki to a web server and publish a link to it.\n\
To enable wiki editing again, see the [[WoaS::Help::Wiki is read-only|Wiki is read-only]] page.\n\
',
'Wiki on a Stick is a client software not designed to be used on a web server; WoaS will anyway recognize that it is being run from a web server and prevent save operations with an appropriate user message informing about the impossibility to save permanent changes.\n\
== Server integration\n\
WoaS 1.0 will offer an API to allow server-side integrations.\n\
',
'== Supported Browsers\n\
Wiki on a Stick is actively supported on the following browsers:\n\
* Firefox 1.5\n\
* Firefox 2\n\
* Firefox 3\n\
* Firefox 3.5+\n\
* Opera\n\
* Internet Explorer 6\n\
* Internet Explorer 7*\n\
* Internet Explorer 8*\n\
* Chrome\n\
* Safari\n\
\n\
/On IE7 (and above) you might want to rename your application to .hta to enable its trusted privileges./\n\
== Limitations\n\
* Firefox (and possibly other browsers, too) cannot save to filenames containing UTF8 characters. Use unix-style filenames instead.\n\
* Internet Explorer 6 and 7 do not support embedded images (that\'s why you will not see button icons).\n\
* Internet Explorer does not allow saving to a network path in the form /\\\\machine\\share\\woas.htm/. To use this wiki over a network with Internet Explorer, map network paths to network drives first.\n\
* Internet Explorer 6 does not allow a fixed menu.\n\
\n\
If you are using Chrome, Safari or Opera you will need the TiddlySaver Java applet, hence you need that Java is enabled in your browser and that it properly works.\n\
== TiddlySaver\n\
The Java applet "TiddlySaver.jar", a very small file, must be placed in the same directory as your WoaS file. In order to use it you will need to give it the necessary privileges by editing your .java.policy file.\n\
\n\
For Windows, the file will be at C:\\Documents and Settings\\your-user-name\\.java.policy. Add the following lines (substituting the directory  as appropriate):\n\
{{{\n\
grant codeBase "file:${user.home}/My Documents/tiddlywiki-folder/*" {\n\
  permission java.io.FilePermission "${user.home}${/}My Documents${/}stickwiki-folder${/}*", "read,write";\n\
};\n\
}}}\n\
On Mac OS X, the file is found at {{{/Users/your-user-name/.java.policy}}}:\n\
{{{\n\
grant codeBase "file:${user.home}/Documents/tiddlywiki-folder/*" {\n\
  permission java.io.FilePermission "${user.home}${/}Documents${/}stickwiki-folder${/}*", "read,write";\n\
};\n\
}}}\n\
It can be tricky creating files whose name starts with a period, so you can use this [[https://stickwiki.svn.sourceforge.net/svnroot/stickwiki/trunk/woas/.java.policy|pre-built .java.policy file]]. The same file is suitable for Macs too, just edit it and delete the "My " bit, leaving just "Documents". Make sure you save it in the right place for each operating system!\n\
\n\
If you have trouble setting up the permissions correctly, you can try granting broader permissions to the applet like this:\n\
{{{\n\
grant codeBase "file://localhost/home/users/Desktop/\n\
TiddlySaver.jar"\n\
 { permission java.security.AllPermission; };\n\
}}}\n\
The TiddlySaver java applet was written by J.Rouston.\n\
',
'Simple single-level lists can be created by using the list buttons in the editor.\n\
* The *{{{*}}}* button inserts the wiki syntax for a bulleted list item\n\
* The *{{{#}}}* button inserts the wiki syntax for a numbered list item.\n\
* The *{{{@}}}* button inserts the wiki syntax for an alphanumeric list item.\n\
* The *{{{List}}}* button wraps HTML ul tags around the selected text to create an unordered list.\n\
* The *{{{List =}}}* button wraps HTML ol tags around the selected text to create an ordered list.\n\
* The *{{{li[*]}}}* button wraps HTML li tags around the selected text to create a list item.\n\
If you\'d like to create mixed lists, nested lists, or lists with additional types of list items, the methods below can be used instead.\n\
== Wiki markup lists\n\
Wiki markup lists are created with between one and five specific characters ({{{@}}}, {{{*}}}, or {{{#}}}) at the beginning of a line, followed by a space, and then whatever text you\'d like the list item to have. Each list must begin with a list item with only one character at the beginning of the line, and there can be no blank lines between entries in the list. To create a blank line beneath a list item, you can insert two HTML {{{\x3Cbr\x3E}}} tags at the end of of the list item\'s text. Wiki and HTML markup are accepted in list items.\n\
=== Alphanumeric List\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
@ Test\n\
@ Test\n\
@ Test\n\
@@ Test\n\
@@@ Test\n\
@@@@ Test\n\
@ Test\n\
@ Test\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
@ Test\n\
@ Test\n\
@ Test\n\
@@ Test\n\
@@@ Test\n\
@@@@ Test\n\
@ Test\n\
@ Test\n\
=== Bulleted List\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
* Test\n\
* Test\n\
** Test\n\
*** Test\n\
**** Test\n\
* Test\n\
* Test\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\x3Cbr\x3E\n\
* Test\n\
* Test\n\
** Test\n\
*** Test\n\
**** Test\n\
* Test\n\
* Test\n\
=== Fancy List\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
* ITEM 1 - ITEM 1 SUBTEXT \x3Cblockquote\x3EITEM 1 MORE SUBTEXT\x3C/blockquote\x3E\n\
* ITEM 2 - ITEM 2 SUBTEXT \x3Cblockquote\x3EITEM 2 MORE SUBTEXT\x3C/blockquote\x3E\n\
* ITEM 3 - ITEM 3 SUBTEXT \x3Cblockquote\x3EITEM 3 MORE SUBTEXT\x3C/blockquote\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\x3Cbr\x3E\n\
* ITEM 1 - ITEM 1 SUBTEXT \x3Cblockquote\x3EITEM 1 MORE SUBTEXT\x3C/blockquote\x3E\n\
* ITEM 2 - ITEM 2 SUBTEXT \x3Cblockquote\x3EITEM 2 MORE SUBTEXT\x3C/blockquote\x3E\n\
* ITEM 3 - ITEM 3 SUBTEXT \x3Cblockquote\x3EITEM 3 MORE SUBTEXT\x3C/blockquote\x3E\n\
=== Numbered List\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
# Test\n\
# Test\n\
## Test\n\
### Test\n\
#### Test\n\
# Test\n\
# Test\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\x3Cbr\x3E\n\
# Test\n\
# Test\n\
## Test\n\
### Test\n\
#### Test\n\
# Test\n\
# Test\n\
=== Numbered Fancy List\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
# ITEM 1 - ITEM 1 SUBTEXT \x3Cblockquote\x3EITEM 1 MORE SUBTEXT\x3C/blockquote\x3E\n\
# ITEM 2 - ITEM 2 SUBTEXT \x3Cblockquote\x3EITEM 2 MORE SUBTEXT\x3C/blockquote\x3E\n\
# ITEM 3 - ITEM 3 SUBTEXT \x3Cblockquote\x3EITEM 3 MORE SUBTEXT\x3C/blockquote\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\x3Cbr\x3E\n\
# ITEM 1 - ITEM 1 SUBTEXT \x3Cblockquote\x3EITEM 1 MORE SUBTEXT\x3C/blockquote\x3E\n\
# ITEM 2 - ITEM 2 SUBTEXT \x3Cblockquote\x3EITEM 2 MORE SUBTEXT\x3C/blockquote\x3E\n\
# ITEM 3 - ITEM 3 SUBTEXT \x3Cblockquote\x3EITEM 3 MORE SUBTEXT\x3C/blockquote\x3E\n\
== HTML Lists\n\
HTML lists work the same way as they do in any web page. Specifying the list type can be done in the {{{\x3Col\x3E}}}, {{{\x3Cul\x3E}}}, or {{{\x3Cli\x3E}}} tags, depending on how you need to use them. Wiki markup is accepted in list items.\n\
=== Specifying list type in the &lt;ol&gt; tag\n\
This method is useful when an entire list will use one list item type. This way you only need to specify the type once, and all the list items can be entered normally.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col style="list-style-type:lower-alpha;"\x3E\n\
\x3Cli\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli\x3Elower-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col style="list-style-type:lower-alpha;"\x3E\n\
\x3Cli\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli\x3Elower-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col style="list-style-type:upper-alpha;"\x3E\n\
\x3Cli\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli\x3Eupper-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col style="list-style-type:upper-alpha;"\x3E\n\
\x3Cli\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli\x3Eupper-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col style="list-style-type:decimal;"\x3E\n\
\x3Cli\x3Edecimal\x3C/li\x3E\n\
\x3Cli\x3Edecimal\x3C/li\x3E\n\
\x3Cli\x3Edecimal\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col style="list-style-type:decimal;"\x3E\n\
\x3Cli\x3Edecimal\x3C/li\x3E\n\
\x3Cli\x3Edecimal\x3C/li\x3E\n\
\x3Cli\x3Edecimal\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col style="list-style-type:lower-roman;"\x3E\n\
\x3Cli\x3Elower-roman\x3C/li\x3E\n\
\x3Cli\x3Elower-roman\x3C/li\x3E\n\
\x3Cli\x3Elower-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col style="list-style-type:lower-roman;"\x3E\n\
\x3Cli\x3Elower-roman\x3C/li\x3E\n\
\x3Cli\x3Elower-roman\x3C/li\x3E\n\
\x3Cli\x3Elower-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col style="list-style-type:upper-roman;"\x3E\n\
\x3Cli\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli\x3Eupper-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col style="list-style-type:upper-roman;"\x3E\n\
\x3Cli\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli\x3Eupper-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
=== Specifying list type in the &lt;ul&gt; tag\n\
This method is useful when an entire list will use one list item type. This way you only need to specify the type once, and all the list items can be entered normally.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cul style="list-style-type:circle;"\x3E\n\
\x3Cli\x3Ecircle\x3C/li\x3E\n\
\x3Cli\x3Ecircle\x3C/li\x3E\n\
\x3Cli\x3Ecircle\x3C/li\x3E\n\
\x3C/ul\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cul style="list-style-type:circle;"\x3E\n\
\x3Cli\x3Ecircle\x3C/li\x3E\n\
\x3Cli\x3Ecircle\x3C/li\x3E\n\
\x3Cli\x3Ecircle\x3C/li\x3E\n\
\x3C/ul\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cul style="list-style-type:disc;"\x3E\n\
\x3Cli\x3Edisc\x3C/li\x3E\n\
\x3Cli\x3Edisc\x3C/li\x3E\n\
\x3Cli\x3Edisc\x3C/li\x3E\n\
\x3C/ul\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cul style="list-style-type:disc;"\x3E\n\
\x3Cli\x3Edisc\x3C/li\x3E\n\
\x3Cli\x3Edisc\x3C/li\x3E\n\
\x3Cli\x3Edisc\x3C/li\x3E\n\
\x3C/ul\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cul style="list-style-type:none;"\x3E\n\
\x3Cli\x3Enone\x3C/li\x3E\n\
\x3Cli\x3Enone\x3C/li\x3E\n\
\x3Cli\x3Enone\x3C/li\x3E\n\
\x3C/ul\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cul style="list-style-type:none;"\x3E\n\
\x3Cli\x3Enone\x3C/li\x3E\n\
\x3Cli\x3Enone\x3C/li\x3E\n\
\x3Cli\x3Enone\x3C/li\x3E\n\
\x3C/ul\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cul style="list-style-type:square;"\x3E\n\
\x3Cli\x3Esquare\x3C/li\x3E\n\
\x3Cli\x3Esquare\x3C/li\x3E\n\
\x3Cli\x3Esquare\x3C/li\x3E\n\
\x3C/ul\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Cul style="list-style-type:square;"\x3E\n\
\x3Cli\x3Esquare\x3C/li\x3E\n\
\x3Cli\x3Esquare\x3C/li\x3E\n\
\x3Cli\x3Esquare\x3C/li\x3E\n\
\x3C/ul\x3E\n\
=== Specifying list type in the &lt;li&gt; tag\n\
This method is useful when creating a fancy list with more than one list item type.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
\x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
\x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
\x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
\x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
\x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
\x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
\x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
\x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
\x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
\x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
\x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
\x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
\x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
\x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
\x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
\x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
\x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
\x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
\x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
\x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
\x3C/ol\x3E\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
\x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
\x3C/ol\x3E\n\
=== Mixed HTML list\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
   \x3Col\x3E\n\
   \x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
      \x3Col\x3E\n\
      \x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
         \x3Col\x3E\n\
         \x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
            \x3Col\x3E\n\
            \x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
               \x3Col\x3E\n\
               \x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
                  \x3Col\x3E\n\
                  \x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
                     \x3Col\x3E\n\
                     \x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
                        \x3Col\x3E\n\
                        \x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
                        \x3C/ol\x3E\n\
                     \x3C/ol\x3E\n\
                  \x3C/ol\x3E\n\
               \x3C/ol\x3E\n\
            \x3C/ol\x3E\n\
         \x3C/ol\x3E\n\
      \x3C/ol\x3E\n\
   \x3C/ol\x3E\n\
\x3C/ol\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
\x3Col\x3E\n\
\x3Cli style="list-style-type:lower-alpha;"\x3Elower-alpha\x3C/li\x3E\n\
   \x3Col\x3E\n\
   \x3Cli style="list-style-type:upper-alpha;"\x3Eupper-alpha\x3C/li\x3E\n\
      \x3Col\x3E\n\
      \x3Cli style="list-style-type:circle;"\x3Ecircle\x3C/li\x3E\n\
         \x3Col\x3E\n\
         \x3Cli style="list-style-type:decimal;"\x3Edecimal\x3C/li\x3E\n\
            \x3Col\x3E\n\
            \x3Cli style="list-style-type:disc;"\x3Edisc\x3C/li\x3E\n\
               \x3Col\x3E\n\
               \x3Cli style="list-style-type:lower-roman;"\x3Elower-roman\x3C/li\x3E\n\
                  \x3Col\x3E\n\
                  \x3Cli style="list-style-type:none;"\x3Enone\x3C/li\x3E\n\
                     \x3Col\x3E\n\
                     \x3Cli style="list-style-type:square;"\x3Esquare\x3C/li\x3E\n\
                        \x3Col\x3E\n\
                        \x3Cli style="list-style-type:upper-roman;"\x3Eupper-roman\x3C/li\x3E\n\
                        \x3C/ol\x3E\n\
                     \x3C/ol\x3E\n\
                  \x3C/ol\x3E\n\
               \x3C/ol\x3E\n\
            \x3C/ol\x3E\n\
         \x3C/ol\x3E\n\
      \x3C/ol\x3E\n\
   \x3C/ol\x3E\n\
\x3C/ol\x3E\n\
',
'= Table syntax\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
{|\n\
| CELL1 || CELL2\n\
| CELL1 || CELL2\n\
|}\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
{|\n\
| CELL1 || CELL2\n\
| CELL1 || CELL2\n\
|}\n\
\n\
\x3Cdiv class="woas_help_text"\x3EOr use this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
{|\n\
| CELL1 || CELL2\n\
|-\n\
| CELL1 || CELL2\n\
|}\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
{|\n\
| CELL1 || CELL2\n\
|-\n\
| CELL1 || CELL2\n\
|}\n\
\n\
The line that starts with {{{|- }}} is a comment line. You can type some text after it which will only be visible when viewing the source:\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
{|\n\
| CELL1 || CELL2\n\
|- This is a comment.\n\
| CELL1 || CELL2\n\
|}\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
{|\n\
| CELL1 || CELL2\n\
|- This is a comment.\n\
| CELL1 || CELL2\n\
|}\n\
== Header rows\n\
Tables can have a specially formatted header row created by adding a pipe followed by a plus symbol and a space before the title text (example: {{{|+ Title}}}), and can contain internal and external [[WoaS::Help::Links|wiki links]].\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
{|\n\
|+ TITLE\n\
| *HEADER1* || *HEADER2* || *HEADER3*\n\
|-\n\
| CELL1 || CELL2 || CELL3\n\
|-\n\
| CELL1 || CELL2 || CELL3\n\
|-\n\
| CELL1 || CELL2 || CELL3\n\
|-\n\
| CELL1 || || CELL3\n\
|}\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
{|\n\
|+ TITLE\n\
| *HEADER1* || *HEADER2* || *HEADER3*\n\
|-\n\
| CELL1 || CELL2 || CELL3\n\
|-\n\
| CELL1 || CELL2 || CELL3\n\
|-\n\
| CELL1 || CELL2 || CELL3\n\
|-\n\
| CELL1 || || CELL3\n\
|}\n\
\n\
\x3Cdiv class="woas_help_text"\x3EOr use this code in a page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
{|\n\
|+ TITLE\n\
| *HEADER1* || *HEADER2* || *HEADER3*\n\
| CELL1 || CELL2 || CELL3\n\
| CELL1 || CELL2 || CELL3\n\
| CELL1 || CELL2 || CELL3\n\
| CELL1 || || CELL3\n\
|}\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
{|\n\
|+ TITLE\n\
| *HEADER1* || *HEADER2* || *HEADER3*\n\
| CELL1 || CELL2 || CELL3\n\
| CELL1 || CELL2 || CELL3\n\
| CELL1 || CELL2 || CELL3\n\
| CELL1 || || CELL3\n\
|}\n\
= Extended customization of layout\n\
Styling, formatting, and alignment can be used to control the look and behavior of tables. All example tables on this page use table comment lines ( {{{|-}}} ) to make it easier to see what is involved in creating the tables. These lines are not necessary when creating your tables.\n\
== Add some custom CSS rules to the wiki\n\
To create a custom table defined by [[WoaS::Help::CSS|CSS]], add some table rules to the wiki CSS using a class name of your choosing.\n\
* \x3Cdiv class="woas_help_text"\x3EUse these CSS rules in your wiki, replacing CLASS_NAME with the class name you\'d like to use, and CSS_RULES with the rules you\'d like to define for the table, the caption, the headers, the cells, and a [[#Styling table cells|special cell]]:\x3C/div\x3E\x3Cbr\x3E{{{\n\
table.CLASS_NAME {CSS_RULES}\n\
caption.CLASS_NAME {CSS_RULES}\n\
table.CLASS_NAME th {CSS_RULES}\n\
table.CLASS_NAME td {CSS_RULES}\n\
table.CLASS_NAME td.special {CSS_RULES}\n\
}}}\x3Cbr\x3ESee the [[#The CSS rules used by the example tables|custom CSS rules]] used by the examples on this page.\n\
== Assign a class to a table\n\
When custom CSS rules have been added to the wiki, you can replace the default {{{{|}}} table opening line with a custom one to assign the custom class to the table.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EOpen a table with this line of code:\x3C/div\x3E\x3Cbr\x3E{{{\n\
{| class="CLASS_NAME"\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo use a custom class for the table.\x3C/div\x3E\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|} \n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|} \n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|} \n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|} \n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
== Alignment\n\
Tables are aligned to the left by default, but alignment can be controlled by surrounding the cell contents with extra spaces or tabs. Forcing content to the left is not necessary, but it may help to use forced alignment for debugging complex tables.\n\
\n\
{|\n\
| *Alignment* || *Example result* || *Effect*\n\
| {space}text{space} || text || default\n\
| {space}text{space}{space} || text  || text is aligned to the left\n\
| {space}{space}text{space} ||  text || text is aligned to the right\n\
| {space}{space}text{space}{space} ||  text  || text is centered\n\
|}\n\
== Captions\n\
Placement of the caption determines whether it\'s above or below the table.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a table, replacing CAPTION with the caption of the table:\x3C/div\x3E\x3Cbr\x3E{{{\n\
|+ CAPTION\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo add a caption to a table.\x3C/div\x3E\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
|+ caption above\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
|+ caption above\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
|+ caption above\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
|+ caption above\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|+ caption below\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|+ caption below\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|+ caption below\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|+ caption below\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
== Empty cells\n\
Empty cells can be created by inserting just one space after a pipe in your table.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample plain table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| || cell 2 || cell 3\n\
|-\n\
| cell 1 || || cell 3\n\
|-\n\
| cell 1 || cell 2 || \n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| || cell 2 || cell 3\n\
|-\n\
| cell 1 || || cell 3\n\
|-\n\
| cell 1 || cell 2 || \n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample fancy table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| || cell 2 || cell 3\n\
|-\n\
| cell 1 || || cell 3\n\
|-\n\
| cell 1 || cell 2 || \n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| || cell 2 || cell 3\n\
|-\n\
| cell 1 || || cell 3\n\
|-\n\
| cell 1 || cell 2 || \n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
== Headers\n\
In default tables, table header cells ({{{\x3Cth\x3E}}}) are created by surrounding the cell content in asterisks. In custom tables, use a single {{{=}}} symbol before the cell content to change the table data cell ({{{\x3Ctd\x3E}}}) into a table header cell {{{\x3Cth\x3E}}}, which can be styled differently through CSS.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
\n\
Placement of table header cells ({{{\x3Cth\x3E}}}) can be anywhere in a table.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| *cell 1* || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || *cell 3*\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| *cell 1* || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || *cell 3*\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || =cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || =cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
\n\
To get the contents of a cell to start with an equal symbol, use an HTML comment ( {{{\x3C!-- --\x3E}}} ) before the equal symbol:\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| \x3C!-- --\x3E=cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || \x3C!-- --\x3E=cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| \x3C!-- --\x3E=cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || \x3C!-- --\x3E=cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| \x3C!-- --\x3E=cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || \x3C!-- --\x3E=cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| \x3C!-- --\x3E=cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || cell 2 || \x3C!-- --\x3E=cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
== Spans\n\
By removing all contents in a cell you can cause the content in the cell to the left or right of it to span more than one column.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| *cell 1* || cell 2 || cell 3\n\
|-\n\
| *cell 1* || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| *cell 1* || cell 2 || cell 3\n\
|-\n\
| *cell 1* || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || cell 2 || cell 3\n\
|-\n\
| =cell 1 || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || cell 2 || cell 3\n\
|-\n\
| =cell 1 || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| cell 1 || cell 2 || cell 3\n\
|-\n\
| cell 1 || span last 2 columns ||\n\
|-\n\
||| span just last 2 columns ||\n\
|-\n\
| span all columns ||||\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
== Styling table cells\n\
Definitions can be used within tables to style the cells. A definition affects only the cells *following* it. If you wish to apply the definition to the entire table, insert it directly beneath the table opening tag.\n\
=== Method 1 - define styles in the wiki CSS\n\
This method requires that you add a custom "special" [[WoaS::Help::CSS|CSS rule]] to the wiki so that any table cell in the "special" class will use that rule. See the *table td.special* rule in the [[#The CSS rules used by the example tables|custom CSS]] used by this page for an example.\n\
\n\
You can add a "special" class definition by using {{{|$ class="special"}}} in a table. The definition can be used by any row below the definition by adding {{{==}}} before the contents of a cell.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
|$ class="special"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
|$ class="special"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
|$ class="special"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
|$ class="special"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
=== Method 2 - define styles on the fly\n\
You can add a style definition by using {{{|$ style="CSSRULE"}}} in a table. The definition can be used in any row below the definition by adding {{{==}}} before the contents of a cell.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || cell 2 || ==cell 3\n\
|-\n\
| cell 1 || ==cell 2 || cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
\n\
Multiple style definitions can be added to a table. The first definition can be used by adding {{{==}}} before the contents of a cell. The second definition can be used by adding {{{===}}} before the contents of a cell. The third definition can be used by adding {{{====}}} before the contents of any cell. And so on.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:#ff00ff"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:#ff00ff"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:#ff00ff"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:#ff00ff"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
=== Method 3 - combination of method 1 and method 2\n\
These examples use a combination of method 1 and method 2. The first definition can be used by adding {{{==}}} before the contents of a cell. The second definition can be used by adding {{{===}}} before the contents of a cell. The third definition can be used by adding {{{====}}} before the contents of any cell. The fourth definition can be used by adding {{{=====}}} before the contents of any cell. And so on.\n\
\n\
\x3Ctable width="100%"\x3E\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample default table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{|\n\
|-\n\
|$ class="special"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:silver"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{|\n\
|-\n\
|$ class="special"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:silver"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| *cell 1* || *cell 2* || *cell 3*\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\n\
\x3Ctr\x3E\x3Ctd width="40%"\x3E\x3Cdiv class="woas_help_text"\x3EExample custom table:\x3C/div\x3E\x3C/td\x3E\x3Ctd width="60%"\x3E\x3Cdiv class="woas_help_text"\x3EUse this code to create the table:\x3C/div\x3E\x3C/td\x3E\x3C/tr\x3E\x3Ctr\x3E\x3Ctd valign="top"\x3E\n\
{| class="mycustomtable"\n\
|-\n\
|$ class="special"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:silver"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
\x3C/td\x3E\x3Ctd valign="top"\x3E\n\
{{{\n\
{| class="mycustomtable"\n\
|-\n\
|$ class="special"\n\
|-\n\
|$ style="background:springgreen"\n\
|-\n\
|$ style="background:silver"\n\
|-\n\
|$ style="background:cyan"\n\
|-\n\
| =cell 1 || =cell 2 || =cell 3\n\
|-\n\
| ==cell 1 || ===cell 2 || ====cell 3\n\
|-\n\
| ====cell 1 || =====cell 2 || ===cell 3\n\
|-\n\
|}\n\
}}}\n\
\x3C/td\x3E\x3C/tr\x3E\x3C/table\x3E\n\
== The CSS rules used by the example tables\n\
These are the custom CSS rules used by the example tables on this page:\x3Cbr\x3E\x3Cbr\x3E{{{\n\
/* CUSTOM CSS FOR custom tables */\n\
table.mycustomtable {\n\
	color: #404040;\n\
	background-color: #fafafa;\n\
	border-collapse: collapse;\n\
	border-spacing: 0px;\n\
	border: 1px solid #6699CC;\n\
	font-family: Verdana, sans-serif, Arial;\n\
	font-size: 11px;\n\
	font-weight: normal;\n\
	/*UNCOMMENT THE WIDTH LINE BELOW TO CONTROL THE WIDTH OF THE TABLE*/\n\
	/*width: 500px;*/\n\
}\n\
caption.mycustomtable {\n\
	color: #404040;\n\
	border: 1px solid #6699CC;\n\
	text-align: center;\n\
	width: 580px;\n\
}\n\
table.mycustomtable th { \n\
	color: #404040;\n\
	background-color: #BEC8D1;\n\
	border-bottom: 2px solid #6699CC;\n\
	border-left: 1px solid #6699CC;\n\
	font-weight: bold;\n\
	text-indent: 2px;\n\
}\n\
table.mycustomtable td {\n\
	color: #404040;\n\
	border-top: 0px;\n\
	border-right: 0px;\n\
	border-bottom: 1px solid #9CF;\n\
	border-left: 1px solid #9CF;\n\
	text-indent: 2px;\n\
}\n\
table.mycustomtable td.special {\n\
	background-color: #ff00ff;\n\
}\n\
\n\
/* CUSTOM CSS FOR DEFAULT TABLES */\n\
table td.special {\n\
	background-color: #ff00ff;\n\
}\n\
}}}\n\
\x3C!-- NOTE: BELOW ARE CUSTOM CSS RULES EMBEDDED ON THIS PAGE FOR USE BY THIS PAGE. --\x3E\n\
\x3Cstyle type="text/css"\x3E\n\
/* CUSTOM CSS FOR custom tables */\n\
table.mycustomtable {\n\
	color: #404040;\n\
	background-color: #fafafa;\n\
	border-collapse: collapse;\n\
	border-spacing: 0px;\n\
	border: 1px solid #6699CC;\n\
	font-family: Verdana, sans-serif, Arial;\n\
	font-size: 11px;\n\
	font-weight: normal;\n\
	/*UNCOMMENT THE WIDTH LINE BELOW TO CONTROL THE WIDTH OF THE TABLE*/\n\
	/*width: 500px;*/\n\
}\n\
caption.mycustomtable {\n\
	color: #404040;\n\
	border: 1px solid #6699CC;\n\
	text-align: center;\n\
	width: 580px;\n\
}\n\
table.mycustomtable th { \n\
	color: #404040;\n\
	background-color: #BEC8D1;\n\
	border-bottom: 2px solid #6699CC;\n\
	border-left: 1px solid #6699CC;\n\
	font-weight: bold;\n\
	text-indent: 2px;\n\
}\n\
table.mycustomtable td {\n\
	color: #404040;\n\
	border-top: 0px;\n\
	border-right: 0px;\n\
	border-bottom: 1px solid #9CF;\n\
	border-left: 1px solid #9CF;\n\
	text-indent: 2px;\n\
}\n\
table.mycustomtable td.special {\n\
	background-color: #ff00ff;\n\
}\n\
\n\
/* CUSTOM CSS FOR DEFAULT TABLES */\n\
table td.special {\n\
	background-color: #ff00ff;\n\
}\n\
\x3C/style\x3E\n\
',
'[[Special::TOC]]This wiki accepts wiki and HTML links.\n\
== Wiki links\n\
Below are methods for creating links using wiki syntax.\n\
=== Anchor link\n\
You can use a special anchor link to link to a heading on the current page. After clicking an anchor link, use the browser\'s back button to return to where you were on the page.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing HEADING NAME with the name of the heading you\'d like to link to:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[#HEADING NAME]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create an anchor link.\x3C/div\x3E\n\
=== Email link\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing USERNAME with the name of the person, SERVER with the name of their server, and LABEL with the text you\'d like displayed as a link:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[mailto://USERNAME@SERVER|LABEL]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
[[mailto://USERNAME@SERVER|LABEL]]\n\
=== Email link with subject\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing USERNAME with the name of the person, SERVER with the name of their server, SUBJECT with the subject of the email, and LABEL with the text you\'d like displayed as a link:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[mailto://USERNAME@SERVER?subject=SUBJECT|LABEL]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
[[mailto://USERNAME@SERVER?subject=SUBJECT|LABEL]]\n\
=== External link (labeled)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing URL with the address of the web page, and LABEL with the text for the link:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[URL|LABEL]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a labeled external link like this one:\x3C/div\x3E\n\
[[http://www.gnu.org/|Click here for GNU]]\n\
=== External link (plain)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing URL with the address of the web page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[URL]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a plain external link like this one:\x3C/div\x3E\n\
[[http://www.gnu.org/]]\n\
=== Image as link\n\
==== Base64 image as link\n\
See the [[WoaS::Help::Images|Images]] page.\n\
==== Image as link to wiki page\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing IMAGENAME with the name of an embedded image page, and PAGENAME with the name of a page in this wiki:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[I\x3C!-- --\x3Enclude:\x3C!-- --\x3E:Image:\x3C!-- --\x3E:IMAGENAME|style="cursor:pointer" oncl\x3C!-- --\x3Eick="go_\x3C!-- --\x3Eto(\'PA\x3C!-- --\x3EGENAME\')"]]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create an image that links to a page in this wiki.\x3C/div\x3E\n\
==== Image as link to web page\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing Image::IMAGENAME with the name of an embedded image page, and URL with the address of a web page:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[In\x3C!-- --\x3Eclude:\x3C!-- --\x3E:Image:\x3C!-- --\x3E:IMAGENAME|style="cursor:pointer" border="0" onc\x3C!-- --\x3Elick="win\x3C!-- --\x3Edow.o\x3C!-- --\x3Epen(\'URL\')"]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create an image that links to a web page.\x3C/div\x3E\n\
=== Include link\n\
You can include the contents of another page of this wiki in the current page by using an include link.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PAGENAME with the name of the page you\'d like to include:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::PAGENAME]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo include the contents of another page in the current page.\x3C/div\x3E\n\
=== Internal action link (labeled)\n\
These are internal wiki actions in the form of links:\x3Cbr\x3E\x3Cbr\x3E\n\
{|\n\
| *Use this code in a page:* || *To create this:*\n\
| {{{[[Special::All Pages|All pages]]}}} || All pages listing\n\
| {{{[[Special::Backlinks|Backlinks]]}}} || Listing of pages linking to page\n\
| {{{[[Special::Dead Pages|Dead links]]}}} || Pages without any link to them\n\
| {{{[[Special::Delete Page|Delete page]]}}} || Delete page prompt\n\
| {{{[[Special::Duplicate Page|Duplicate page]]}}} || Duplicate page\n\
| {{{[[WoaS::CSS::Custom|Custom CSS]]}}} || Custom CSS\n\
| {{{[[Special::Go to|Go to...]]}}} || Go to page prompt\n\
| {{{[[Locked::|Locked pages]]}}} || Listing of encrypted pages\n\
| {{{[[Special::Main Page|Main page]]}}} || Main Page (whatever title it has)\n\
| {{{[[Special::New Page|New page]]}}} || New page prompt\n\
| {{{[[Special::Orphaned Pages|Orphaned pages]]}}} || Orphaned pages listing\n\
| {{{[[Special::Recent Changes|Recent Changes]]}}} || Recently changed pages listing\n\
| {{{[[Special::Search|Search]]}}} || Search into pages interface\n\
| {{{[[Tagged::Syntax|Syntax pages]]}}} || Pages tagged with \'Syntax\'\n\
| {{{[[Tagged::|Tagged pages]]}}} || Pages which contain tags\n\
| {{{[[Unlocked::|Unlocked pages]]}}} || Listing of pages without encryption\n\
| {{{[[Untagged::|Untagged pages]]}}} || Listing of pages without any tag\n\
|}\n\
=== Internal link (labeled)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PAGENAME with the page you want to link to and LABEL with the link text:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[PAGENAME|LABEL]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a labeled internal link.\x3C/div\x3E\n\
=== Internal link (plain)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PAGENAME with the page you want to link to:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[PAGENAME]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a plain internal link.\x3C/div\x3E\n\
== HTML links\n\
Below are methods for creating links using HTML syntax.\n\
=== Alert box link (button)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing MESSAGE with the content for the alert, and BUTTONTEXT with the text for your button:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cscript type="text/javascript"\x3E\n\
function alertme () {alert("MESSAGE");}\n\
\x3C/script\x3E\n\
\x3Cinput type=button value="BUTTONTEXT" onClick="alertme()"\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a button that opens an alert.\x3C/div\x3E\n\
=== Alert box link (labeled)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing MESSAGE with the content for the alert, and LABEL with the text for your link:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Ca href=\'javascript:alert("MESSAGE");\'\x3ELABEL\x3C/a\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a labeled text link that opens an alert.\x3C/div\x3E\n\
=== Anchor links to anywhere on a page\n\
With a combination of HTML and wiki syntax, you can create anchor links to anywhere on a page, rather than just to headings.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing NAME with the name of the anchor:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Ca name="NAME"\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3EUse this code somewhere else on the same page, replacing NAME with the anchor name:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[#NAME]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create an anchor link to anywhere on a page.\x3C/div\x3E\n\
\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3EOr use this code somewhere else on the same page, replacing NAME with the anchor name and LABEL with the text for the link:\x3C/div\x3E\x3Cbr\x3E{{{\n\
[[#NAME|LABEL]]\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a labeled anchor link to anywhere on a page.\x3C/div\x3E\n\
=== Edit page link\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing LABEL with the text for your link:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Ca class="woas_link" onclick="woas.ui.edit()" title="Edit this page"\x3ELABEL\x3C/a\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a link that opens the current page in the editor.\x3C/div\x3E\n\
=== External link (button)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing BUTTONTEXT with the text for your button, and URL with the address of the web page:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cinput type="button" value="BUTTONTEXT" onclick="window.open(\'URL\');"\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a button that opens an external link in another tab or window.\x3C/div\x3E\n\
=== Internal link (button)\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing BUTTONTEXT with the text you want on the button and PAGENAME with the page you want to link to:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cinput value="BUTTONTEXT" onclick="woas.go_to(\'PAGENAME\')" type="submit" /\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo create a button that opens an internal link in another tab or window.\x3C/div\x3E\n\
',
'Wiki on a Stick offers various ways to use images in your pages. You can link to image files located on the Internet, network, or local drive, or embed image files into the wiki.\n\
\n\
The [[Image::]] namespace listing displays an image gallery. Each image is displayed on a green background so that you can tell if it contains transparency: if all you can see is a thin green border around the image (using the default CSS) then it is not transparent; if the green background shows through then it is.\n\
\n\
The image currently highlighted will be opened in its own page if clicked. This page shows it on a normal page background and provides info on the image and its use in the wiki.\n\
\n\
The format of both the image gallery and the images can be controlled using [[WoaS::Help::CSS|custom CSS]].\n\
== Standard WoaS syntax\n\
All supported browsers can display embedded images, except for Internet Explorer 6 & 7; IE 6 & 7 may have this capability added in a future version. If you are using a Gecko-based browser like Firefox you can also embed images. This capability will hopefully be added for other browsers in the future.\n\
\n\
Embedded images allow the wiki to be self-contained within a single file, but means that each image takes up 33% more space than its original file size as it is stored with Base64 encoding. Excessive use of images could affect performance, especially on less capable hardware.\n\
=== Embed an image in the wiki\n\
This wiki provides an interface for embedding images. Each image will be given its own page, which you can use in an include link to insert the image anywhere in this wiki.\n\
\x3C\x3C\x3Cwoas.note: It is recommended that the image file extension be retained in the image name. Image export operations will then preserve the extension when writing out the file and that will help those browsers that infer the mime type of the image from the file extension.\x3E\x3E\x3E\n\
\x3Cspan class="woas_help_text"\x3EReplace NAME in these instructions with the name of your image:\x3C/span\x3E\n\
\n\
*From the default menu*\n\
# Click the *New Page* link in the menu.\n\
# Type {{{Image::NAME}}} into the box that comes up. This will bring up the image embedding interface.\n\
# Browse to the image on your computer.\n\
# Click the *Embed* button.\n\
*From any page*\n\
# Create an include link for a new image by typing {{{[[Include::Image::NAME]]}}} into a page, or click the editor\'s *Image* button and type in a name for the image.\n\
# Click the *Save* icon in the navigation bar to save the page.\n\
# Part of the include link you just created will be red, indicating that the image doesn\'t exist yet.\n\
# Click on the red part of the link to launch the embedding interface.\n\
# Browse to the image you\'d like to embed.\n\
# Click the *Embed* button. You\'ll be taken to the *Image::NAME* page with your image embedded in it.\n\
=== Use an embedded image\n\
Once an image is embedded, you can use the same include link you used to add the embedded image to include the image anywhere in the wiki. \n\
# Create a new page or open an existing page in the editor by clicking the *Edit* icon in the navigation bar.\n\
# Create an include link for an already embedded image. There are two ways you can do this:\n\
## Use this code wherever you like in a page: {{{[[Include::Image::NAME]]}}}\n\
## Or click the editor\'s *Image* button and type in the name of the image.\n\
# Click the *Save* icon in the navigation bar to save the page. The image should now be where the include link was.\n\
== Using HTML\n\
=== Add an external image from the internet\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing URL with the full link to the image, to add an external image from the internet:\x3C/div\x3E\n\
{{{\n\
\x3Cimg src="URL" /\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EExample:\x3C/div\x3E\n\
{{{\n\
\x3Cimg src="http://www.gnu.org/graphics/heckert_gnu.small.png" /\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EResult:\x3C/div\x3E\n\
\n\
\x3Cimg src="%2BxS6AAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH1AkZAiQF53xPugAAGFFJREFUeNrNXH9MVHe2%2F1QmS1OSaTrJmOUdZnYWybDsBJgSUXgID62BpayUEvz1RMKqhfW39Wmrr2qtGik1UnWFwKoLq0RXKWgJ9EHUrU83UOFJkUgDD3iwYKA7E9hlwmxmdoac98e9M8zcucMPq%2B1%2B%2F5mZ7733ez%2F3fM%2F3nM8553vnJcY%2FWVPMfNgyOm6xAAHBUKnUPzSi8QdfP%2B6xeHQE6mLiU4Oe%2FVbO%2FuG%2FjluhfFWp0s3wdC%2FJz9poXWNbgCFaF6IKETq%2BdT4d6Wl%2FGpixW%2FdMcIZr73bZVa8tBEz%2FMNmhjF2yMnweiNrK7ryamh7rK4%2Fh6ivjv94bOG88fYVNuoz4aKVLFwZ6vmnt1GVsDJY7mX1aczal1TuE7476hzZm7j6TueFM8yQz28oiEm7z%2FJrtpDb3kU%2Fv2PW12k0dvmf7IBrKpxT3LRsTiEJX7VlKQjNm7mvksX20aUiAa5sToPsJK5qZebLjwqal%2B%2B472NZ83iQc6d2jFYfyaJJZc5acC9q%2FEcDjyoWBgXfaXP0Bhk4AStUgCg4q2g%2F1rE8PGf%2FqyjXNjHNlDQIwfryuYK%2Bi6UrfU6FTtajTDuXuzcKSenyw%2F%2FiamfRodFtb%2Bgk1AGS0e66y8BMxn5%2Bwbtmi7KqtW1SqQu2VNgSE9fTMvPLOjq5UPLgWfTwMFUcVqZ2DQOo3w%2BKxRTFme%2FJ2wHmqZPUphV89ehipvy58uyrOk757cmhogpmZJyfFk86PMbNtiHdkzjJd9dpQ7YY%2FMvOxVZcn2HFhRT1PHFmXFJeUJgyuHRDOypz0p0f1%2BoRuZp7ovn8jQkTk0qih1ubmIYfnhRMfaJtn02hjvfAMvZIDjrXC6PmCsuozx%2BT1qGGb7jM1cCdP%2BJlqABa9BYw%2BaOnsmwKAgDBDVFSYCrAP999pmCpOn23RN717Imv612DPoBUIMRgAc4oZAJCs%2BXFyNFo3%2FrwqSEaP2leHfKYGnMmDAIDwuwBgqalrgy42epEmwDzc0%2FX1uOvsRb%2FYMgev0rT%2FtfSfAhifGP22a1xl%2BDHsXf2qNzcaTHZ8e%2FYeACi%2FUqIlb1m5wgfReKrzi2AAJYXC78KNgKXkoj02PdVjRZm7vwXwmvqnyrmZRmtTe78TQEiQ%2BmdRgj0cbbzZnnw0DLiXAwAoOAw0bNty2Eez87UdzMzNemGKI23MNUbtnl5%2BAa17q77IwSyYudAhZq6hRqlm11MZM3dkC3gyL4%2BxbQ%2FlDvALao8S0kx8O4WIiOKuM%2FMm%2FYg3ItviVQ5m3iSsyhFmnsx2WYIX0iY3GHuZO3YSEdEx5rHIXG9Ep7W9zMwrBNDM7Mg0dvCLbI53jEPMQ0REtI6Z613ztkBwxhfzwgBAWGZqAAcHq6NnU9vx4eHh0WcmZqWGAjteFSgFgPTET5wejO2ifQcAjNoBAEqg9kZ12Ezjjd5p6RqcAgDoYt9aJuF9zrtffj1sgea1sPhUlX9IbxYeFZbsIAAcSm14y7367XFZhwHg7CkAUJYsty7LOjwDnq7iO4YlP9colYD9ac%2BXLaqNWzysgbP2VEBWjC4QFnNf%2B734LfH%2Bhml%2Fuy56cxMA1MUA2Gypdq%2F%2BW1oTM%2FMxIiJaMcBcZJz0rwFjW0OPeBmFkdMRxlvuX0%2FSjNen%2FY2tJmGDXwuyJ5sdB4iIjB3MfJ%2BG3Jq9KZeZuUZY%2BWPMptAZltkfIzb4cBpbkXaP%2BAwVoflj3ip8OeKCn6FGQjuY84mIIpiZF1cwMysAWO%2BdAoAoQZY98TgfnOV3xioO798tfLM%2F7jEDqpCohQh87638jEs6wLm%2F9j8LAGC0fdAeHGUAoNiYWNB%2FXDbCCM6qisYwAGgAIFVwqcx8Wys8n5GIiM7z2AwiuqCtF%2BnuplCRH1DKBRvzZLa%2Bnh3vUFzFCNtqMoUji4%2BZmJknM99xyI7WEemwaYmI3mdmvq13%2Bf7jbXUAgG11AJBcVXLxK3%2Fk%2FuLx0nQAzsrKQc9u3bkYOLd9kTHYCSBgZVSl2U328nYrAWtOyG9kx1t2KiALAIrXALD8%2FG44sABAT4wYIgAADKjL8AeoQgB0L%2FmoFyAMvl0LxW%2FfrOsE4nOCmk4tWe06Yi9f9jkQVNX5oTyizp8pAeApAChDuiEiWiR4%2B3sAoNk12rXcD6CGo0fTAeu7OYPSI1O7LgKlGev3pra0Ve8Navhql5vwjG8vsCLoD3UlciMa2pW7AeDsAwAI6xH1iJo9iOx%2FcSP5WfoPQ08yc28cybYLQmxyPyJpYmQr6Y8Zpw8lmZgf6e%2FLxSlp7EggIoocYuYDOwUvMopgAM4yAEDiLzAYLE%2Fo%2B7akHgRa04flBXj0%2BKEAAImXBsuCS4ttF%2FOmjWb%2Fm32IKdwuc2HwX6EoAIAJCwD1qDBrTgQAUJQGAsCwE1Z5cmjeuOgc0LTe6s8ulI8qACB%2BYzWwpgqleR5OZ6MZWalb7D7XBA4DdQDwngGASkQEwd8ZjgLAYDUgKyJr9o8uKdCSb%2FfvXESumToKIPE966BHDD2cY0VhgKx2t7QAiCkAgCCLC5Eg3zU6APhE%2Fpb2HEuVCj15U7PnWRRBAJAX1BLr6QoPQVF%2Bs0nmqhIACBDW%2BbgLkRkAhjMGAWDchKcy1737TaUG5nXWmQjBhLi4VAAQFG72siHVN6Ap3C8lL0%2BDEA8AbW%2F3uboWAIANgDWrCwDwa9nI%2BXjduWhYc8wzUp5vhY8oqxkArIvGvY4e7kHWG7ucktUSAiGmsVg9EAnCDqrSAIB6O4KHfSbuWvnhVGB%2F10x4VMHiY2rKD%2FUBj3uy7nkr4jY7PhqVWKX%2BMASuAbDoZrQHomDh4cIblgFQmhCOdqllPLCxACis8w%2FHcKqts2HUJPyIL%2BmEZdf2WonO9XwIZXlpq1dfd6zzbBmg%2Fmw6T7YAQKCgAKrdAPpTS6JUn3sP1bor8ThwzcfoKjWipkRdalofjIWGBpeKZ3Wt%2Bvf1H1dXnYrxPL%2FqBgzHd3vOpaVt5d1TU4D5PADAFCCuj4WCejTtAgB7w%2FbVlf%2Bh9rKMYeUKNB3wHDxgSXKMQQn0tY0G6cTQEOs%2BTRSp8JXi4uXQAQhshyGk06XP%2B9XL1%2FQXXJtmJjcMOuHel%2FARAMu%2FiF4k%2B6SQoxBMfi5PROR7GPpeY5KJ%2BWHotFMwbqpx%2BxmvrNYB%2FWUHM%2FMto4s2DtFOZh6pyRcGj%2Bhl3jrNTCYiG8VohOgWM%2B9MEznkzk3M%2FLdc8Z4HmK%2FTBQ9AxgHmh0Koq82%2FNeDNdE578ckLEQlnupn3nHf36K8KnwNbiYgowcSOd3Jdz7N1FbONiCjz6ggz86p8EVHZYiGou72BiOgMMx8g15hXIxIGmG%2FriYi0B3zo7FXy7po4n0lJ109nuyWXvcf17Vao6HQdW5OamZkdB4xDzJN6F2FjjigSEd2nvwiQVhARFU0yO%2FZR%2FgAz966jXBNzhZaIaJM05h5ZG0nkItUdpyf4PjPz2OWE3D1J3S4cIudkl5yTBpgvaNddbr6QkNTLlzO103mqAWoUEU1oa5iZeYeY%2Blp1nbnGSCnZCWSsYR7LJyIy1nvDKVuXnUBERrd0QkPjSMBs23Tm9CZmnixad5Ivh7ovvC3oUj1z774Vcbm%2FszFHiloUaWLmy9oJV0brzbBzAK4cdFuXJsBa12kLNqwMRO3RcQDJ57xDwcKS4KgmAKs%2FdfXcK38AMSi49iC8%2Fxwsq%2FqBm7FN22pd1u%2BTc4K92p7s4hOvCzY1JyxWBax23nTFa2f0NmbuuHUyQZTS9AJqFnKGJyUT1kgJk%2FeJiFo9Oov2pDEzPyky7otoZT5JRGttzEdS3Asz0xUrdDBz75MxQWoUMSGsy%2BvueE38ziYxeUQdbOplZu4VszcfSDXaSI3cLOYQPEPCDma2%2FW7Ph93MtgiitQ5mHiGTO1nuym%2Fqn3Cvnkg0OFTEzHwkwjadG9mQJgzosjiRWqLzzA9FZpotjW0ekZG5mcgoptp7mzsczMwD%2BzwIKxHVDzEzR0wLst5t0zqSPBhxqInZFHqaXREkkJfXEg88rnazdQCFwSEbBYesPKeQRpGIBwYRXq4Bxq81DauUPbG%2FB6BzDrodVCcQcOPO3w%2Fq8Oq0w09PFz2N2SOtmpcOAGcDt3jmIVNfuQk0dcF5zsNTvCwyhFPrJUW3SFVpPMzvxhco4Lz0ID05GLAmn0gF8PjEJRe9PngFsTeB9hjEF08nI4aX%2BXI%2B9X8rgcF%2FO7xlmh8Bh9o%2BB1L37m3zjHhEQDESQPjy1ep44JWq7QqM1yZXrQ8GEJR6BQCix4%2B7zrIBGQBiYJ%2FwSJxoVkrxpGdoKgB8qMnzYqKJ6SeWK4HKFgSbpA9xUPL7QVWdDiIbV7mLGppaIensJkVB2PUrIQ7WGDyuTpUyW4Fi1951OWBRRjhhPQDg9ZanbVLe%2F4Z3%2Fsf%2Bub1apujntFnGAWDjqItnqpAIy73q6os3yj1PTPa%2Bbr%2B6FQDMR1cnSqqi6hO7EtcjGuiyBOm8uOJeya3fmubSACztw%2F1f9kMzMoWm9QDiU1tFnV2Ee2X3pgAEPvB8goWG6dFDnuJX6QcBOHcGfuTFswEgK%2BdoDwC0aOpygAD3VfGSdKQgQpe%2BFb%2Bec%2FBiPzD8clT8RQsAHG1xGX6U3J0CAPvBG54DrHbLECd0OmVYqRMoaSlX%2BiDC4UV5ZgABDeExwHvu7gJZFuviptVuSl5YXdcHAJoYcdrCFgX8qQAA3gio9rx0jRqAUoOjyoD4gwZArcDnpz6KkatmjSxeJRAXh36fLZQWbyCtlhLkUwCu5HOctugvJhetcrEA16f2SBwRUe%2FJOAmDIaLr1NyYxtwscMUjfqpZT%2FSZQiktd4zXhnbk0wdE5%2BXz46vELxsSJnlCS0S0j1nKVs5rQ4mI%2FsLeaUDOJqJHW5td0Cu0Bxz%2B6rQP9UkDzMxjzOevc3ZKPWnHZBE1u2Q0ZNzk4GNEpH%2FEvT4p%2BVwioiOOh42SUrCeqGLsichidtDpGSrHHcZIkc1MMm%2FoPUm58pN2%2BkP36Gmrmrlm37FudhxzdEtOm4hb1dzdmhD5RNJfQ7RTZAPXjYtvz1jLHkmjrS7hP%2BFsqpFHlFkxnYr9XULmmVvNzVfXPuQyH1lqUyIpdKfP9TsodIKZe88sDT0yMXMtG85zZxUZecKKd4ajUzZPMhpb5xmIDbYPDr8cnq525lVJzywsMSS%2FuaZTmkW0b2vK0nV1jqrXyNQNffAP7NFSSlGzjbmDNsiL6DxNyHUXnfStx6QcY15R79ufRpTy4X25DC7kEt9FSUTalK25VCFf9lkcKbf%2BLlyWucEjbTefXOe7VaGe%2FNXuIN89cHnnCi3RkOzB65Qy96rVgTRuJqMPWBM9mh8iZmbHUqN80TyOsueOaCziqk2fHbpCahq0ZX4uWDBDykzzsmx%2F2fB86miqguP2jNgmZUald3%2F0FX%2FZsRkeLztOtuwbmrQvYR7FxonQottJ7CjTrmr1yhtrEzasG5vfrHGaHKLJFdT8RGubB6QP9A9pgvlJGqVd8ChsNa6NoxvzQzSgTZPp3UofMKfcnweiAe0mGmJmR022loxF04bjDD2ROd3%2FPjbngalE397CuvDDQE5dop%2FNYXXtFqjDohI9bKJuzTWYNYAiK8veXVdetT4%2B%2BBUAPbV1bxvmpUf7KNe3GnFBCNEcv5QtVAzla8mYnZ0ZSUZP92OK9Mj%2BjLzvKk8sPeOY1%2BpvpiTfC4pIzFV1nJStlunPCPsInuyg%2FAlP95Y0ycwD9YL62YaGhoaGxuZrj4roso9Sb6UVLtWsMflesiL04bTeRsR5%2BI5G%2FdI9G4xESU9mVzu%2FiPaISSUPESTQhunJ8jW5j%2Bjk7RUUeUQQ7cg6yp42%2BU%2ByKWLD1asrZt2zNAOiVUkSs39AS%2BSYaagKOqKNKLp%2F%2FoJ7z2CoVMyTmRueGVENbfX82ft%2BKOmJZhzqDBFdFciey51G7pM8w%2FXQWS2Z%2FOq3FpfDHa3au1oaOhG0%2FfWNM%2FuLMAA6wNz8j4AYIUJLX5KzrdTrDgZ796ybP2RXcRJliia%2F%2BViKlogijph4bJZZm4yI1E9wt56IaIe4kib3ZXpR3SF%2FrHRmGdlz%2Bt8UHq1vVycQaFiyLDEQUKnGB2faTBK0vaE6CHesgNJ%2Bs%2FMzNQAEneq6FpzjSURn3foih%2BhG%2F%2FpCBQB05ZgRMPWeK4gMb2mXIrKWjGqiXOmOgm4AMQBif3O6cmeVMLRBYpftsyGSYyNNykJFz5UGc2WWeXtnNFTTitLic%2Bq5mAx3%2FkXx6d%2BB%2BO0BiFF%2BVNpyRe52TxH8LDJqD%2F9ToZAuKDgIj5Ka2lVB88gxpXqqu0IN4OB2uxpI33vpV7LRefizyGiqPac7Jt0ApL83XTMFAPxYemrGJcAyLJaDRAqmVAPA9qB2mT1UleqoZ5HR0XNRB3XAOFQArJ6IfEQeCCCw88ZUeRDQN%2BiZP1Ns7orxMSqbzccVeJbV79mI3Ib%2FtCQe9iBlW5kn3pEYA5%2BUwWQmveOY1WYvmJ0pB06njhr8UOzDX9%2FBjbckxkCaiRvPa8sonV1Ec5CR21%2F26knrx8DdSrD5sKm%2FSSK0SDo2F8q5YB5hRVhP3tQd%2BUNvBZVZpAH5q167bzYX2M8dnstd5oMISIbFz5FtxTPtZ3%2F87r81RdVm4TkhMns6U38bjtM1fo3x4NnUjM6VWGSY42PPNq168iBZk5Tv77zr5IeMTTR3jDDz%2B1Q2t9BlVkRx5JnZCE3wt3wdCQkzrmxHLuVPPhfNVnvOGkIG179bIW9qTwyem9EU%2F%2F7ivW3PRY9C4LlFLBot1Ycvymt9%2BtkZd3HgF6vvmp8HojAMeJrChvK34UcWhaqC8Zk3tMP5PDS7niTpKxuRH658X%2FKehUTDT2vnlHZ6abY36kZj0ebtYGNHdRrd5jDZ%2FaRRpV6%2Bw9TS1j%2FyD7yiekXV%2F3hKPfN%2BZtl3auRa3NMSb49V8bEVSL0kd%2B6VQ0hPjl4kMOKulpZ%2BL5N1Yk7v5M2O6EBVzse%2BKdjkKvkNzoUtADRqmEemAJ1BFwiYx0dHR1GQp5mbgZwd0YP1IV9JncIWU%2FUSfxb6TkvfUztUi6Jfj1%2Fo7i0u%2FkaJ52Sz2RFJ0lz%2BYj%2FlEv%2Btkeb81sDsfk2xGo1SbUc65tdC8Pe5njoHT7sR1ZIeHbrwwtocEOneGLwnKd3iUNv8btMH9XNEhB2QuLItKvPbb5fU9s0d0V1l2FxPnQPvRWzi3S4vcqOpvtjX2QaIoa%2FfZjGZLRYgJHj4Tuqcwb80l7ege1L%2B9Zq0rysVwJu%2F9ePB%2Bga%2FGex7Op1DV36he54yQnjepTvSvQxKAPiiMk%2FGILV1edCF4Kjw4JdfiVc9XxnBujLgrrRGdm10vNai%2FhoQXwoV29k%2FeEVQlSvnvdjmZrbuaz%2BU6b0tZN0ca23eoaOWKKVxcuBqxNzioXmyWnc8%2B0eZUJaWMrNtK4149%2FeeueVgZo7Q214cIs6NGJF2lRGdZMfpCAqVv8REK%2FgFIppMSpuU5uApcoLfF194k8330jO8JDjnCDLoM4tkc%2FUVIEOJmwCGK%2FpqD8kw1uLA48%2FgRuZRAzJ%2BIKkK0C9drwYJ71d6MgZR%2B7pfnIwAXXVTsZcvUePrQ04xZ5Yq4WOjrQCQjgcvwtNOhyXXPvd0cKrKIFRmBcqkHQDgawB4xW%2Be4DllIsI%2Bq%2FbMd0bfCEb7XWGz0og0Bdot7PcLebGIoK5ubfCEdDcdAHbrgHuSXFejAmY8PqRc%2FiI1W6x%2B1EvzVJRiMhKleW2T6NBeHtl0W0%2F1L9AeTVPmL73N4Fqixhryrp09MmoHMiN89iu%2FIEQ85L3QHb%2BktY4EItKeFMU0cUxLS%2BOI9kw8AyB%2B6bv%2FS8zmpqCe1tVTAALLVwKWi8IWu4DS9GcabsF3xeMsb0IUlpQGALBbgTvLioUVH%2FZsgL4zohvxxxF4CEivBICFaN3syo%2F0dP0giB7vHVWtvhsNCBGUBcXTe2D3O38IRP%2BL452f6gBcqxMKMX%2BePta5zfkDIHodQvHDIjj5WqtnLeeLjHY4HwNm5%2FeIKGyvsOX4mgVRAMzv%2FtrzaGdGiO4U%2BioU36dm7xp%2FDAAPsP09APjiE0l5Sbm%2FeP3GeY2o%2BI6IFL9pFWKl%2FaMBUwB6pEFUlvMPwd%2BvPcISAMiCRbNb7uhTZ2n8%2FMYLOPpcEhqhE08SYv%2FPLSCl0%2BUK1JeXf79rzd0%2BUvUpTi2D8CcTUNWJeYLEuiXzHek5yQiICfzRjzL%2F3I31if%2FD%2BNtPihe0TwGa5d0tpp%2FOT1dfer7%2Fx1b5ifXjZdX3Hk%2B9sUP35TfDdvXPlhnmOcRzRoTx2i7N%2BmDnoPnpT5Y82wgv%2FdP9Z92CfzZA%2BH8h6HFxmnJRXwAAAABJRU5ErkJggg%3D%3D" /\x3E\n\
=== Add a local image from your hard drive\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PATH with the full path to the local file you\'d like to display:\x3C/div\x3E\n\
{{{\n\
\x3Cimg src="file://PATH" /\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3ETo add a local image from your hard drive.\x3C/div\x3E\n\
\n\
* *Linux example using a default Kubuntu image:*{{{\n\
\x3Cimg src="file:///usr/share/icons/default.kde/16x16/actions/stop.png" /\x3E\n\
}}}\n\
* *Windows example using a default Windows 7 image:*{{{\n\
\x3Cimg src="file://localhost/C:/Documents and Settings/All Users/Documents/My Pictures/Sample Pictures/Blue hills.jpg" /\x3E\n\
}}}\n\
=== Use a data:URI image\n\
It is always better and advisable to embed an image instead of using a data:URI image, mostly because embedded images can be reused inside the wiki and do not garble the edit window when editing the page.\n\
\n\
However if you want to use a data:URI image anyway you can do it by directly adding this XHTML snippet:\n\
{{{\n\
\x3Cimg src="data:image/EXTENSION;ENCODING,ENCODED_IMAGE" /\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EExample:\x3C/div\x3E\n\
{{{\n\
\x3Cimg src="" /\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EResult:\x3C/div\x3E\n\
\x3Cimg src="" /\x3E\n\
\n\
A famous online service to create such URIs is [[http://software.hixie.ch/utilities/cgi/data/data|The data: URI kitchen]]. The recommended encoding to be used in WoaS is base64.\n\
=== Create a data:URI image button\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing YOUR_MESSAGE with the message to be displayed and DATA_URI_GOES_HERE with the data:URI of your image:\x3C/div\x3E\n\
{{{\n\
\x3Cinput type="image" onclick=\'alert("YOUR_MESSAGE")\' src="DATA_URI_GOES_HERE"\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EExample:\x3C/div\x3E\n\
{{{\n\
\x3Cinput type="image" onclick=\'alert("Hello world!")\' src="" /\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EResult:\x3C/div\x3E\n\
\x3Cinput type="image" onclick=\'alert("Hello world!")\' src="" /\x3E\n\
',
'== Importing a WoaS XHTML wiki\n\
Another Wiki on a Stick can be imported into the current wiki by using the Special::[[WoaS::Help::Special::Import|Import]] page. \x3C\x3C\x3Cwoas.note: To import a version 0.9.6B or earlier WoaS file you will need a WoaS 0.11.x release as this WoaS cannot import it.\x3E\x3E\x3E\n\
Help pages and the WoaS Javascript code are not imported so it is always best to import an older wiki into a current one as this will also update the older wiki.\n\
# Access [[Special::Import]] either directly or from [[Special::Advanced#Maintenance]]\n\
# Click the *Browse* button and select the wiki you\'d like to import\n\
# Choose the settings you\'d like to use.\x3C\x3C\x3Cwoas.note: If you are importing WoaS \x3C 0.12.0 it is much better to import CSS manually and not automatically because CSS definitions have changed\x3E\x3E\x3E\n\
# Click the *Import* button.\n\
# A warning will pop up letting you know that this will overwrite pages with the same title and asking if you\'re sure.\n\
# Click the *OK* button if you\'re sure. Otherwise, click the *Cancel* button.\n\
== Importing WSIF\n\
This method is used to import pages that have been exported using the WSIF format (see the [[WoaS::Help::WSIF|WSIF]] page for more information). Help pages are not imported so it is always best to import WSIF content into a current WoaS file.\n\
# Access [[Special::ImportWSIF]] either directly or from [[Special::Advanced#Maintenance]]\n\
# Click the *Browse* button and select the .wsif file to import\n\
# Choose the options to use\n\
# Click the *Import WSIF* button\n\
',
'\x3Cinput style="font-size:.75em;" id="menu_string_to_search" type="text" size="19" onkeydown="return menu_key_hook(event)" onfocus="menu_search_focus(true)" onblur="menu_search_focus(false)" /\x3E&nbsp;\x3Cinput style="font-size:.75em;" class="woas_button" type="button" value="Search" onclick="menu_do_search()" /\x3E\n\
',
'== Exporting into XHTML static pages\n\
/See: [[WoaS::Help::Special::Export|Special::Export]] for a more detailed explanation./\n\
\n\
Your WoaS pages can be exported into web-compatible XHTML, CSS and eventually attachment files/images; generated pages do not use Javascript for rendering and can be efficiently cached by web servers.\n\
# Access [[Special::Export]] either directly or from [[Special::Advanced#Maintenance]]\n\
# Modify the export directories if necessary\n\
# Choose the settings for the export.\x3C\x3C\x3Cwoas.note: Note that the "Run before exporting but do not export the Javascript" option means that Javascript is run and then the XHTML is exported, but the Javascript source code itself is not. This is useful if you have Javascript that does custom parsing.\x3E\x3E\x3E\n\
# Click the *Export XHTML* button. A confirmation will pop up\n\
== Exporting into WSIF\n\
/See: [[WoaS::Help::Special::ExportWSIF|Special::ExportWSIF]] for a more detailed explanation./\n\
\n\
# Access [[Special::ExportWSIF]] either directly or from [[Special::Advanced#Maintenance]]\n\
# Modify the export directory if necessary\n\
# Choose the settings for the export.\x3C\x3C\x3Cwoas.note: Note that you can export into a single WSIF file or multiple WSIF files. Embedded files are exported as individual files unless you choose not to export them as external file blobs, in which case they\'ll be embedded in the WSIF file(s).\x3E\x3E\x3E\n\
# Click the *Export WSIF* button. A confirmation will pop up, telling you how many pages were exported\n\
\n\
The WSIF file(s) in the export directory can now be copied, shared, or stored for backup purposes. See also [[WoaS::Help::WSIF|WSIF]].\n\
',
'\x3Cbig style="color:#0A0"\x3E%1 had a little %2\x3C/big\x3E\n\
',
'Transclusion is the name wikis use to describe [[WoaS::Help::Include wiki page|including a wiki page]] inside another wiki page. WoaS can do something much more powerful than simple transclusion: instead of just displaying the contents of the included page as is, you can change how the content is displayed depending on how you write the link.\n\
\n\
This method requires that you create a page to be used as a template. This page must contain variables represented by %1, %2, %3, and so on.\n\
\n\
You can then create a transclusion link or links to that page by creating a normal include link with the values for the variables added after the page name. Each value must be preceded by a pipe ({{{|value}}}). The values you define in the link will be used from left to right to replace the numbered variables on the page you\'re including.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code, replacing PAGENAME with the name of the page to be included, and VALUE1 and VALUE2 with the values you\'d like the two variables to have when the included page is displayed:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::PAGENAME|VALUE1|VALUE2|VALUE3]\x3C!-- --\x3E]\x3C/div\x3E\n\
== Examples\n\
These examples use the [[WoaS::Help::Template transclusion::Example]] page which contains two variables. The contents of that page are:\n\
{{{\n\
\x3Cbig style="color:#0A0"\x3E%1 had a little %2\x3C/big\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3EThis code:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::WoaS::Help::Template transclusion::Example|Mary|lamb]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3EResults in this transclusion:\x3C/div\x3E\n\
[[Include::WoaS::Help::Template transclusion::Example|Mary|lamb]]\n\
\x3Cdiv class="woas_help_text"\x3EWhile this code:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::WoaS::Help::Template transclusion::Example|Fred|snack]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3EResults in this transclusion:\x3C/div\x3E\n\
[[Include::WoaS::Help::Template transclusion::Example|Fred|snack]]\n\
\x3Cdiv class="woas_help_text"\x3EIf an unneeded parameter is supplied:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::WoaS::Help::Template transclusion::Example|Bob|Jane|Jack]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3EThe extra parameter is simply ignored:\x3C/div\x3E\n\
[[Include::WoaS::Help::Template transclusion::Example|Bob|Jane|Jack]]\n\
\x3Cdiv class="woas_help_text"\x3EIf a needed parameter is not supplied:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::WoaS::Help::Template transclusion::Example|Mary]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3EThe missing parameter shows up in the transclusion (note the {{{%2}}}):\x3C/div\x3E\n\
[[Include::WoaS::Help::Template transclusion::Example|Mary]]\n\
== Wiki and HTML code in transclusion\n\
Some wiki code and HTML tags are accepted in the values.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code:\x3C/div\x3E\n\
\x3Cdiv class="woas_help_code"\x3E[\x3C!-- --\x3E[Include::WoaS::Help::Template transclusion::Example|&#042;Mary&#042;|&#042;lamb&#042;.&lt;br&gt;&lt;br&gt;Its &#047;fleece&#047; was white as &#095;snow&#095;.]\x3C!-- --\x3E]\x3C/div\x3E\n\
\x3Cdiv class="woas_help_text"\x3ETo create this:\x3C/div\x3E\n\
[[Include::WoaS::Help::Template transclusion::Example|*Mary*|*lamb*.\x3Cbr\x3E\x3Cbr\x3EIts /fleece/ was white as _snow_.]]\n\
== Infinite recursion\n\
Infinite recursion happens when you create an include link to the current page or to another page that that has an include link to the current page. The included page will be repeated multiple times followed by the include link itself being displayed in bold red text surrounded by infinity symbols like this:\n\
\n\
\x3Cfont color="red"\x3E*{{{\u221e [[Include::PAGENAME]] \u221e}}}*\x3C/font\x3E\n\
\n\
You should always prevent infinite recursions from happening.\n\
',
'= Special::ExportWSIF\n\
The [[Special::ExportWSIF]] page allows you to export wiki content into one or more [[WoaS::Help::WSIF|WSIF]] files for backup, sharing with others, or importing into an updated WoaS file.\n\
== File generation options\n\
===Relative path for WSIF file, including filename\n\
The box contains a default path and filename when the page is loaded. This is the relative path and name of the file for the exported WSIF file. A relative path is one that starts in the same directory the WoaS file is in; {{{temp/file.wsif}}} is a relative path, {{{/temp/file.wsif}}} is not; {{{c:\\temp\\file.wsif}}} and {{{c:temp\\file.wsif}}} are also incorrect. The file name can have any extension or none at all, but the /wsif/ extension will let you know that it\'s a WoaS data source file. The path may be entered in Windows or UNIX format, but will be converted to the correct format upon entry.\n\
\n\
If just a filename is entered the file will be created inside the directory the WoaS file is in. The path can additionally specify a directory path relative to the location of the wiki. WoaS will create the specified subdirectory only if you are using a Gecko-based browser like Firefox. If you are using a different browser you must create the subdirectory yourself before saving the file.\n\
\x3C\x3C\x3Cwoas.note: If you enter the name of an existing file that file will be overwritten on the next save; any associated files will also be overwritten if /multiple files/ mode is selected.\x3E\x3E\x3E\n\
The filename will be used as the index page name when exporting to multiple files.\n\
===Export as multiple WSIF files (instead of saving all pages to a single wsif file)\n\
If the box is checked, the content of all the user pages will be exported into multiple WSIF files, with each page being exported into its own WSIF file. All the files will be numbered using the wiki\'s page numbering method, and an index.wsif file will be created in the same directory to act as a reference for which page is in which numbered file. If the box is not checked, the content of all the user pages in the wiki will be exported into one WSIF file.\n\
===Include ALL pages from this WoaS (instead of only user created pages)\n\
If the box is checked, all wiki pages will be exported. If the box is not checked, only user-created pages will be exported.\n\
== Other options\n\
===Author\n\
If you type a name into this box, a *woas.author:* line will be added near the top of the WSIF file to display the name you typed as the author of the file. If nothing is in the box, the *woas.author:* line will not be added to the WSIF file.\n\
',
'The [[Special::ImportWSIF]] page allows one to import a [[WoaS::Help::WSIF|WSIF]] file which contains one or more wiki pages; wiki pages imported into the *WoaS::* namespace will offer special features.\n\
== Existing pages\n\
Available options for imported pages whose title collides with existing page titles:\n\
* *Erase all user pages before import process*\n\
* *Ignore* - do not import colliding pages\n\
* *Overwrite* - replace existing page with imported page\n\
* *Ask before overwrite* - ask for each colliding page before replacing\n\
== Security\n\
General Javascript security options to prevent possibly malicious code from being imported.\n\
* *Comment Javascript tags*: convert all {{{\x3Cscript ...\x3E...\x3C/script\x3E}}} tags to {{{\x3Cdisabled_script ...\x3E...\x3C/disabled_script\x3E}}}\n\
* *Comment macro definition/call*: comment all macro definitions/calls {{{\x3C\x3C\x3C...\x3E\x3E\x3E}}} so that they are not parsed/called\n\
* *Import pages of the WoaS:: namespace*: allow importing hotkeys, plugins, aliases and custom CSS\n\
\n\
*Note:* if you have enabled some Javascript code by mistake you should enable *safe mode* in [[Special::Options]]\n\
',
'Lines that do not start with \'$\' are ignored.\n\
\n\
Hotkeys\n\
-------\n\
\n\
$SAVE     s\n\
$EDIT     e\n\
$PRINT    p\n\
$HELP     h\n\
$GOTO     g\n\
\n\
Cancel key is by default escape (ASCII 0x1b)\n\
$CANCEL   0x1b\n\
\n\
Back key is by default backspace (ASCII 0x8)\n\
$BACK     0x8\n\
\n\
Custom hotkeys\n\
--------------\n\
\n\
You can define custom hotkeys here and the associated\n\
Javascript function in a plugin (see Help).\n\
This example is disabled:\n\
\n\
;$CUSTOM(home)    m\n\
',
'/*******************************\n\
 | CRITICAL LAYOUT/DISPLAY CSS |\n\
 | ALTERATION CAN BREAK LAYOUT |\n\
 | EVEN BY CHANGING THE ORDER  |\n\
 ******************************/\n\
\n\
/* hidden layout */\n\
.woas_hide, #loading_overlay, #woas_wait_text, #woas_pwd_mask,\n\
#woas_custom_accesskeys {\n\
	display: none\n\
}\n\
\n\
/* general layout design */\n\
\n\
/* a quick browser CSS reset - consider \'* {\' as better suited */\n\
body, div, textarea, pre, ul, ol, li {\n\
	margin: 0px;\n\
	padding: 0px;\n\
	border-width: 0px\n\
}\n\
#woas_header_wrap {\n\
	width: 100%;\n\
	z-index: 1\n\
}\n\
#woas_footer_wrap, #woas_page_wrap {\n\
	margin-left: 13em; /* to match menu wrap */\n\
}\n\
.woas_edit #woas_footer_wrap {\n\
	margin-left: 0em\n\
}\n\
#woas_menu_wrap {\n\
	width: 13em; /* to match page and footer wrap */\n\
	_float: left; /* for IE6 */\n\
}\n\
#woas_header_wrap, #woas_menu_wrap {\n\
	position: absolute\n\
}\n\
.woas_fix_m #woas_menu_wrap, .woas_fix_h #woas_header_wrap {\n\
	position: fixed;\n\
	_position: absolute; /* IE6 can\'t do fixed */\n\
}\n\
#woas_pwd_mask {\n\
	position: absolute;\n\
	height: 100%;\n\
	width: 100%;\n\
	z-index: 100\n\
}\n\
#woas_page {\n\
	position: relative\n\
}\n\
\n\
/* control disabling of navbar icons (or text if no images) */\n\
\n\
.woas_no_back #woas_back, .woas_no_fwd #woas_fwd, .woas_no_home #woas_home,\n\
.woas_no_tools #woas_tools, .woas_no_edit #woas_edit,\n\
.woas_no_lock #woas_lock, .woas_no_lock #woas_unlock,\n\
.woas_no_debug #woas_debug {\n\
	display: inline-block; /* IE 6-8 needs this for filter to work */\n\
	-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=15)"; /* IE8 */\n\
	*filter: alpha(opacity=15); /* IE 6/7 */\n\
	opacity: .15; /* all others, including IE9 */\n\
	cursor: default;\n\
	*text-decoration: none; /* for ie7 */\n\
}\n\
\n\
/* select images or text for display */\n\
/* LOOK AT MAKING THESE MORE EFFICIENT by using IDs instead - though dynamic\n\
   creation of controls completely removes need for this ... coming soon */\n\
\n\
.woas_nav a span, .woas_no_img .woas_nav img, .woas_no_img img.woas_nav,\n\
.woas_no_img #woas_debug img, .woas_no_img #woas_top img,\n\
#woas_menu_edit img, #woas_debug span, #woas_top span {\n\
	display: none\n\
}\n\
.woas_no_img .woas_nav a span, .woas_no_img #woas_debug span,\n\
.woas_no_img #woas_top span, #woas_menu_edit span {\n\
	display: inline\n\
}\n\
\n\
/* control read-only and locks */\n\
\n\
.woas_locked #woas_unlock {\n\
	display: inline\n\
}\n\
.woas_ro #woas_edit, .woas_ro #woas_lock, .woas_ro #woas_unlock,\n\
.woas_ro #woas_menu_edit,\n\
.woas_locked #woas_lock, .woas_unlocked #woas_unlock {\n\
	display: none\n\
}\n\
\n\
/* control overall display */\n\
\n\
.woas_view #woas_edit_mode, .woas_view #woas_edit_wrap,\n\
.woas_edit #woas_view_mode, .woas_edit #woas_page_wrap, .woas_edit #woas_menu_wrap,\n\
.woas_pswd #woas_scroll_wrap, .woas_pswd #woas_header_wrap, .woas_wait #woas_scroll_wrap,\n\
.woas_no_mts #woas_mts, .woas_no_log #woas_debug_console {\n\
	display: none\n\
}\n\
.woas_edit #woas_edit_wrap, .woas_view #woas_page_wrap, .woas_view #woas_menu_wrap,\n\
.woas_pswd #woas_pwd_mask, .woas_wait #loading_overlay {\n\
	display: block\n\
}\n\
\n\
\n\
/*****************\n\
 | WOAS STYLING  |\n\
 | SAFE TO ALTER |\n\
 *****************/\n\
\n\
/*\n\
	All measures except borders in em because IE6 doesn\'t resize pixel measures properly\n\
	and IE9 giving some border errors with em measures; exception is 0px.\n\
*/\n\
\n\
/* _BROWSER RESET VALUES */\n\
\n\
ul, ol {\n\
	margin: .75em 0px .75em 1.25em\n\
}\n\
li {\n\
	padding-bottom: .125em\n\
}\n\
li ul, li ol {\n\
	margin: .125em 0px 0px 1.25em\n\
}\n\
/* could also add values for these reset items if needed\n\
div {\n\
}\n\
\n\
pre {\n\
}\n\
*/\n\
\n\
/* BACKGROUND */\n\
\n\
.woas_background, body {\n\
	background-color: #335; /* no color name */\n\
}\n\
\n\
/* BODY */\n\
body {\n\
	word-wrap: break-word;\n\
	font-family: Georgia, verdana;\n\
	text-align: left\n\
}\n\
\n\
/* BUTTONS */\n\
.woas_button, .woas_button_top, .woas_button_editor,\n\
.woas_button_menu, .woas_button_ro {\n\
	background-color: #F0F0F5; /* matches header */\n\
	border: 1px solid #808080; /* grey */\n\
	color: #00008b; /* darkblue */\n\
	cursor: pointer;\n\
	font-variant: normal;\n\
	margin-top: .438em;\n\
	text-align: center\n\
}\n\
.woas_button:hover, .woas_button_top:hover, .woas_button_editor:hover,\n\
.woas_button_menu:hover, .woas_button_ro:hover {\n\
	background-color: #A9A9A9; /* darkgrey */\n\
}\n\
.woas_button_editor {\n\
	margin: .25em 0px 0px 0px;\n\
	padding-left: .188em;\n\
	padding-right: .188em;\n\
}\n\
.woas_button_top {\n\
	position: relative;\n\
	float: right;\n\
	margin: .5em\n\
}\n\
.woas_button_ro {\n\
	margin-left: -1.25em;\n\
	background-color: #FFF0F0\n\
}\n\
.woas_button_menu {\n\
	margin-top: 0.438em;\n\
	width: 100%\n\
}\n\
\n\
/* CONTENT (page layout) */\n\
#woas_content {\n\
	padding: .75em\n\
}\n\
\n\
/* DEBUG CONSOLE */\n\
#woas_debug_log_container {\n\
	border: 1px solid #000; /* black */\n\
	background-color: #F0F0F5; /* matches header */\n\
	margin-top: .375em; /* matches woas_footer padding-bottom */\n\
	padding: .25em 0em .25em .375em\n\
}\n\
\n\
/* textarea cannot contain padding/margins for cross-browser */\n\
#woas_debug_log {\n\
	width: 100%;\n\
	background-color: #F0F0F5; /* matches header */\n\
	resize: vertical;\n\
	overflow: auto;\n\
	overflow-x: hidden; /* for IE */\n\
}\n\
#woas_debug_log_clear {\n\
	margin: .375em 0px 0px\n\
}\n\
\n\
/* EDITOR */\n\
/* no padding/margins/borders in woas_editor textarea for x-browser */\n\
#woas_editor {\n\
	width: 100%;\n\
	resize: vertical;\n\
	overflow: auto;\n\
	*overflow-x: hidden; /* for IE 6/7 */\n\
	outline: none; /* Webkit (Chrome, Safari, etc.) */\n\
	font-size: 100%\n\
}\n\
#woas_editor_container {\n\
	background-color: #fff; /* white */\n\
	border: 1px solid #000; /* black */\n\
	margin-top: 0.5em;\n\
	/* a little spacing for the text */\n\
	padding: 0.5em 0px 0.5em 0.5em\n\
}\n\
.woas_editor_link, #woas_edit_wrap{\n\
	color: #F0F0F5; /* same as header */\n\
}\n\
\n\
/* EXPORT (at end of CSS) */\n\
\n\
/* FOOTER */\n\
#woas_footer {\n\
	*position: relative;\n\
	border: 1px solid #F0F0F5; /* same as header */\n\
	margin-top: 0.75em;\n\
	padding: .375em\n\
}\n\
#woas_footer a {\n\
	font-size: .688em;\n\
	font-weight: bold;\n\
	color: #F0F0F5; /* same as header */\n\
}\n\
#woas_footer_panel {\n\
	position: relative;\n\
	width: 100%;\n\
	line-height: 1em\n\
}\n\
#woas_about, #woas_debug, #woas_top {\n\
	position: absolute\n\
}\n\
#woas_about {\n\
	width: 100%;\n\
	text-align: center\n\
}\n\
#woas_debug {\n\
	left: 0px\n\
}\n\
#woas_top {\n\
	right: 0px\n\
}\n\
\n\
/* HEADINGS */\n\
/* (PVHL: do we really need woas_heading style? Not using so x-browser better) */\n\
h1, h2, h3, h4, h5, h6 {\n\
	margin: .75em 0px .325em;\n\
	padding: 0px\n\
}\n\
/* this misses IE6 */\n\
h1:first-child, #woas_toc + h1, h2:first-child, #woas_toc + h2,\n\
h3:first-child, #woas_toc + h3, h1 + h2, h2 + h3, h3 + h4 {\n\
	margin-top: 0px\n\
}\n\
h1 {\n\
	font-size: 1.438em\n\
}\n\
h2 {\n\
	font-size: 1.25em\n\
}\n\
h3 {\n\
	font-size: 1.063em\n\
}\n\
h4 {\n\
	font-size: 0.875em\n\
}\n\
h5 {\n\
	font-size: 0.75em\n\
}\n\
h6 {\n\
	font-size: 0.625em\n\
}\n\
\n\
/* HELP PAGES */\n\
/* PVHL: this should be in a separate page, like WoaS::CSS::Help */\n\
/*\n\
next three are for layout; no changes allowed except colors;\n\
wraps cannot contain margins, paddings, or borders\n\
*/\n\
.woas_help {\n\
	border-width: 0px;\n\
	height: 100%;\n\
	width: 100%;\n\
	margin: 0px;\n\
	padding: 0px;\n\
	overflow: hidden;\n\
	background-color: #fff; /* white */\n\
}\n\
#woas_help_top_wrap {\n\
	width: 100%\n\
}\n\
#woas_help_body_wrap {\n\
	position: absolute;\n\
	bottom: 0px;\n\
	width: 100%;\n\
	overflow: auto;\n\
	_overflow-x: hidden; /* helps IE6; gets overflow:auto wrong sometimes */\n\
}\n\
\n\
/* end of Help layout CSS; rest can be styled */\n\
\n\
#woas_help_body {\n\
	background-color: #FFF; /* white */\n\
	padding: 1em\n\
}\n\
#woas_help_body ol li {\n\
	margin-bottom: .5em\n\
}\n\
.woas_help_top {\n\
	background-color: #335; /* matches wiki background */\n\
	color: #F0F0F5; /* matches wiki header */\n\
	font-family: Arial Black, Gadget, sans-serif;\n\
	font-size: 1.5em;\n\
	padding: .625em .625em 1em\n\
}\n\
.woas_help h3 {\n\
	margin-bottom: .188em\n\
}\n\
/*\n\
explicit margins are needed for IE6/7 otherwise collapsed under certain circumstances.\n\
*/\n\
.woas_help h1 {\n\
	margin: .5em 0px .25em\n\
}\n\
.woas_help_button {\n\
	float: right;\n\
	margin-left: .625em;\n\
	background-color: #F0F0F5; /* matches background */\n\
	border: 1px solid #808080; /* grey */\n\
	color: #00008b; /* darkblue */\n\
	cursor: pointer\n\
}\n\
.woas_help_button:hover {\n\
	background-color: #A9A9A9; /* darkgrey */\n\
}\n\
.woas_help_code {\n\
	font-family: monospace;\n\
	padding: 0.5em\n\
}\n\
.woas_help_text {\n\
	font-family: lucida;\n\
	color: #048db4;\n\
	font-weight: bold\n\
}\n\
\n\
/* IMAGE GALLERY */\n\
a.woas_img_list, .woas_img_list_first, .woas_img_list_last, .woas_img_list_single {\n\
	display: block;\n\
	padding-bottom: .75em;\n\
	padding-top: 1em;\n\
}\n\
a.woas_img_list:hover, .woas_img_list_first:hover, .woas_img_list_last:hover,\n\
.woas_img_list_single:hover {\n\
	background-color: #efe;\n\
	margin-left: -1em; /* same as woas_page padding */\n\
	margin-right: -1em;\n\
	padding-left: 1em;\n\
	padding-right: 1em;\n\
	text-decoration: none;\n\
}\n\
img.woas_img_list {\n\
	display: block;\n\
	margin-bottom: .625em;\n\
	padding: .5em;\n\
	background-color: #afa\n\
}\n\
\n\
/* INPUT LAYOUT */\n\
.woas_input_wrap {\n\
	margin-top: .75em;\n\
	padding: .625em .625em .625em 1.875em;\n\
	border: 2px solid #F0F0F5; /* matches header */\n\
	text-align: left\n\
}\n\
.woas_input_wrap legend {\n\
	font-size: 1.188em;\n\
	font-weight: bold\n\
}\n\
.woas_input_wrap label input, .woas_input_wrap label select {\n\
	margin: 0px .434em .313em -1.25em\n\
}\n\
.woas_input_wrap label input {\n\
	vertical-align: -0.063em\n\
}\n\
.woas_input_wrap .woas_input_wrap_inline {\n\
	margin-left: .625em\n\
}\n\
.woas_input_wrap .woas_input_wrap_no_left {\n\
	margin-left: 0px\n\
}\n\
.woas_input_wrap .woas_input_wrap_left {\n\
	margin: 0px 0px .313em -1.25em\n\
}\n\
\n\
/* LAST MODIFIED TIMESTAMP */\n\
#woas_mts {\n\
	margin-top: 0.75em;\n\
	color: #F0F0F5; /* same as header */\n\
	font-size: small;\n\
}\n\
\n\
/* LINK */\n\
a {\n\
	cursor: pointer\n\
}\n\
a:hover {\n\
	text-decoration: underline\n\
}\n\
\n\
/* LINK - EXTERNAL */\n\
.woas_world_link {\n\
	color: #006400; /* darkgreen */\n\
	text-decoration: underline\n\
}\n\
\n\
/* LINK - NO PAGE */\n\
.woas_unlink {\n\
	color: #f00; /* red */\n\
}\n\
\n\
/* LINK - PAGE */\n\
.woas_link {\n\
	color: #00f; /* blue */\n\
}\n\
\n\
/* LOCKED PAGE */\n\
.woas_locked #woas_page {\n\
	/* can contain a border */\n\
	border: 2px solid #f00;\n\
}\n\
\n\
/* MAIN TEXT AREA */\n\
#woas_page {/* main text area */\n\
	overflow: hidden;\n\
	margin-bottom: 0.75em;\n\
	background-color: #fff; /* white */\n\
	border: 1px solid #000; /* black */\n\
	padding: 1em\n\
}\n\
\n\
/* MENU */\n\
/*\n\
Add the following CSS to WoaS::Custom::CSS to allow an image icon for edit\n\
instead of the current text icon. I find the text less distracting.\n\
\n\
.woas_no_img #woas_menu_edit img, #woas_menu_edit span {\n\
	display: none\n\
}\n\
.woas_no_img #woas_menu_edit span, #woas_menu_edit img {\n\
	display: inline\n\
}\n\
\n\
*/\n\
#woas_menu_pad {\n\
	margin-right: 1.25em;\n\
	background-color: #fff; /* white */\n\
	border: 1px solid #000; /* black */\n\
	font-size: .75em;\n\
	padding: 1em\n\
}\n\
#woas_menu_edit {\n\
	font-size: .833em;\n\
	float: right;\n\
	margin: -0.25em -0.75em 0px 0.25em;\n\
}\n\
#woas_menu_edit img {\n\
	margin-top: -.5em;\n\
	background-color: none; /* remove temporary IE8 background */\n\
}\n\
\n\
/* MONOSPACED TEXT (except search) */\n\
pre {\n\
	white-space: pre-wrap; /* CSS 3 */\n\
}\n\
.woas_core_page, .woas_nowiki_multiline {\n\
	border: 1px solid #808080; /* grey */\n\
}\n\
.woas_core_page {\n\
	background-color: #F0F0F5; /* same as header */\n\
}\n\
.woas_core_page, .woas_embedded {\n\
	padding: 1.25em\n\
}\n\
.woas_embedded {\n\
	background-color: #9E9EFF\n\
}\n\
.woas_nowiki {\n\
	padding: 0px 0.25em\n\
}\n\
.woas_nowiki, .woas_nowiki_multiline {\n\
	background-color: #F5F5F5\n\
}\n\
.woas_nowiki_multiline {\n\
	margin: 1em 0px;\n\
	padding: .5em\n\
}\n\
\n\
/* NAVIGATION BAR */\n\
.woas_nav img, /* temporary CSS to fix IE8 icon opacity display */\n\
#woas_header_wrap {\n\
	background-color: #F0F0F5; /* no color name */\n\
}\n\
#woas_header {\n\
	padding: 0.75em\n\
}\n\
.woas_fix_h #woas_header {\n\
	border-bottom: 1px solid #fff; /* white */\n\
}\n\
.woas_edit #woas_header {\n\
	border-width: 0px\n\
}\n\
#woas_title {\n\
	line-height: 1;\n\
	font-size: 1.813em;\n\
	font-weight: bold;\n\
	margin-right: .188em;\n\
	text-shadow: #888 0.125em 0.125em 0.065em\n\
}\n\
div.woas_nav { /* navbar icon/text link container */\n\
	float: right;\n\
	margin-top: .188em\n\
}\n\
.woas_nav a { /* navbar links */\n\
}\n\
.woas_nav a span { /* no-image text */\n\
	font-weight: bold;\n\
	font-size: 70%\n\
}\n\
img.woas_nav { /* woas logo */\n\
	float: left;\n\
	margin-right: .375em\n\
}\n\
\n\
/* NOTE MACRO & TEMPLATE::INFO */\n\
.woas_note { /* could be multiples, so use class */\n\
	display: inline-block;\n\
	background: #FFFFAA url() no-repeat .5em .5em;\n\
	border: 1px solid #000;\n\
	margin: 1em 1.25em;\n\
	padding: .75em .75em .75em 2.5em\n\
}\n\
.woas_no_img .woas_note {\n\
	padding-left: .75em\n\
}\n\
\n\
/* PAGE LISTINGS */\n\
.woas_list {\n\
	margin: .188em 0px .25em 1.5em\n\
}\n\
.woas_list_heading {\n\
	margin: .375em 0px 0px;\n\
	font-weight: bold\n\
}\n\
.woas_list_link {\n\
	color: #00008b; /* darkblue */\n\
}\n\
.woas_list_link:hover {\n\
	background-color: #FFFFE0; /* LightYellow */\n\
	text-decoration: none\n\
}\n\
\n\
.woas_list_options {\n\
	float: right;\n\
	padding: .188em .375em;\n\
	background-color: #F0F0F5; /* matches header */\n\
	font-size: .8em\n\
}\n\
\n\
/* PASSWORD (see also encryption) */\n\
#woas_password_desc {\n\
	background-color: #FAFAFB;\n\
	border: 1px solid #000080; /* navy */\n\
	margin: 0px 10%;\n\
	padding: 2em\n\
}\n\
/* mask should not contain borders/padding/margins */\n\
#woas_pwd_mask {\n\
	text-align: center\n\
}\n\
#woas_pwd_query {\n\
	position: relative;\n\
	margin: 0px 10%;\n\
	top: 10%;\n\
	padding-top: 1em;\n\
	background-color: #d6dff7;\n\
	border: 2px solid #666666\n\
}\n\
\n\
/* PRINT  (at end of CSS) */\n\
\n\
/* SEARCH */\n\
#woas_search_results {\n\
	padding-top: 1.5em\n\
}\n\
.woas_search_results {\n\
	font-family: "Courier New", Courier, monospace;\n\
	background-color: #f9f9f9;\n\
	border: 1px solid #aaa;\n\
	clear: both;\n\
	padding: 0.313em;\n\
	margin: .75em\n\
}\n\
.woas_search_highlight {\n\
	background-color: #ff0; /* yellow */\n\
}\n\
\n\
/* TABLE OF CONTENTS */\n\
#woas_toc {\n\
	float: right;\n\
	max-width: 40%;\n\
	margin-left: 2em;\n\
	margin-bottom: 1em;\n\
	border: 1px dashed #aaa;\n\
	background-color: #f9f9f9;\n\
	padding: .75em 1em;\n\
	font-size: 80%\n\
}\n\
#woas_toc_title {\n\
	line-height: 1em;\n\
	font-weight: bold;\n\
	text-align: center\n\
}\n\
#woas_toc_content {\n\
	margin-top: .75em\n\
}\n\
.woas_toc_h1, .woas_toc_h2, .woas_toc_h3,\n\
.woas_toc_h4, .woas_toc_h5, .woas_toc_h6 {\n\
	margin-top: .125em;\n\
	margin-bottom: .125em\n\
}\n\
.woas_toc_h2 {\n\
	margin-left: 1.5em\n\
}\n\
.woas_toc_h3 {\n\
	margin-left: 3em\n\
}\n\
.woas_toc_h4 {\n\
	margin-left: 4.5em\n\
}\n\
.woas_toc_h5 {\n\
	margin-left: 6em\n\
}\n\
.woas_toc_h6 {\n\
	margin-left: 7.5em\n\
}\n\
\n\
/* TABLES */\n\
#woas_page table {\n\
	border: 1px solid #000; /* black */\n\
	border-spacing: 0px\n\
}\n\
#woas_page table td {\n\
	border: 1px solid;\n\
	padding: .313em\n\
}\n\
#woas_page table caption {\n\
	font-style: italic;\n\
	font-weight: bold\n\
}\n\
\n\
/* TAG - CONTAINER */\n\
.woas_taglinks {\n\
	border: 1px solid #aaa;\n\
	margin-top: 1em;\n\
	overflow: auto;\n\
	padding: .5em 1em;\n\
	font-size: 80%;\n\
	text-align: left;\n\
	color: #aaa; /* matches border */\n\
}\n\
\n\
/* TAG - LINKS */\n\
.woas_taglinks \x3E a {\n\
	margin: 0px;\n\
	padding: .125em .313em;\n\
	background-color: #fff; /* white */\n\
	color: #000; /* black */\n\
	text-decoration: none\n\
}\n\
.woas_taglinks \x3E a:hover {\n\
	background-color: #808080; /* grey */\n\
	color: #fff; /* white */\n\
	font-weight: normal;\n\
	text-decoration: none\n\
}\n\
\n\
/* TEXT DECORATIONS (used by editor buttons, but generally available) */\n\
.woas_b {\n\
	font-weight: bold\n\
}\n\
.woas_i {\n\
	font-style: italic\n\
}\n\
.woas_s {\n\
	text-decoration: line-through\n\
}\n\
.woas_u {\n\
	text-decoration: underline\n\
}\n\
\n\
/* WIKI LOADING OVERLAY */\n\
#loading_overlay {\n\
	position: absolute;\n\
	width: 100%;\n\
	height: 100%;\n\
	padding-top: 25%;\n\
	z-index: 100;\n\
	left: 0px;\n\
	top: 0px;\n\
	color: 	#000080; /* navy */\n\
	font-size: large;\n\
	text-align: center\n\
}\n\
\n\
/* WOAS MODIFIER CSS (EXPORT & PRINT)\n\
   (needs to be after other CSS)\n\
*/\n\
\n\
/* EXPORT (modifier: .woas_export) */\n\
.woas_export #woas_header_wrap {\n\
    position: static\n\
}\n\
.woas_export #woas_page {\n\
    margin-bottom: 0px\n\
}\n\
.woas_export #woas_menu_wrap {\n\
	position: relative;\n\
	float: left\n\
}\n\
.woas_export .woas_broken_link {\n\
	color: #000;\n\
	text-decoration: none\n\
}\n\
.woas_export .woas_link {\n\
	text-decoration: none\n\
}\n\
.woas_export .woas_link:hover {\n\
	text-decoration: underline\n\
}\n\
.woas_export_no_menu #woas_page_wrap {\n\
    margin-left: 0px\n\
}\n\
\n\
/* PRINT (modifier: .woas_print) */\n\
#woas_page.woas_print {\n\
	overflow: auto;\n\
	border-width: 0px;\n\
	padding: 0px;\n\
	margin: 0px\n\
}\n\
.woas_print .woas_nowiki_multiline {\n\
	page-break-inside: avoid\n\
}\n\
',
'/* Your CSS customization goes here */\n\
\n\
body {\n\
    font-family: arial,helvetica,sans-serif;\n\
}\n\
\n\
/* code box */\n\
div.code_sample {\n\
    font-family: monospace;\n\
    border-width: 1px; \n\
    border-color: black;\n\
    border-style: dashed;\n\
    background-color: lemonchiffon;\n\
    padding: 0.875em;\n\
}\n\
\n\
div.callout {\n\
    font-family: sans-serif;\n\
    border-width: 1px; \n\
    border-color: black;\n\
    border-style: solid;\n\
    background-color: lemonchiffon;\n\
    padding: 0.875em;\n\
}',
'/* CSS used when loading/saving WoaS; readonly */\n\
body {\n\
	margin: 0px;\n\
	padding: 0px;\n\
	border-width: 0px;\n\
	font-family: Georgia, verdana;\n\
	background-color: #F0F0F5; /* to match layout; no name */\n\
}\n\
#loading_overlay {\n\
	position: absolute;\n\
	z-index: 100;\n\
	left: 0px;\n\
	top: 0px;\n\
	bottom: 0px;\n\
	color: 	#000080; /* navy */\n\
	font-size: large;\n\
	text-align: center\n\
}\n\
#woas_debug_console {\n\
	width: 50%;\n\
	margin: 3em auto\n\
}\n\
#woas_debug_log {\n\
	width: 100%\n\
}\n\
#woas_wait_text, #woas_pwd_mask, #woas_header_wrap, #woas_menu_wrap, #woas_page_wrap,\n\
#woas_edit_wrap, #woas_custom_accesskeys, #woas_footer_panel, #woas_debug_log_clear {\n\
	display: none\n\
}\n\
',
'You can define key bindings for hotkeys (also called \'access keys\') by editing the [[WoaS::Hotkeys]] page.\n\
\n\
Example:\n\
{{{\n\
$SAVE s\n\
$EDIT e\n\
}}}\n\
The *$SAVE* and *$EDIT* definitions identify a WoaS action, while the /\'s\'/ and /\'e\'/ characters identify the associated hotkey.\n\
\n\
See the Wikipedia [[http://en.wikipedia.org/wiki/Access_key|Access key]] entry for details on how different browsers access these keys.\n\
== Custom hotkeys\n\
You can create a custom hotkey associated with a Javascript function that will be called when that hotkey is activated.\n\
\n\
Example:\n\
{{{\n\
$CUSTOM(myfunction)     k\n\
}}}\n\
The /myfunction/ Javascript function will be called (without arguments) when the /\'k\'/ hotkey is activated.\n\
',
'All pages of the [[WoaS::Plugins::]] namespace are WoaS plugins; plugins are executed when loading WoaS and remain active during WoaS usage. The WoaS project has plugin examples available for code syntax highlighting, MathML display, and charting; these are found in the /Plugins/ directory of the download. One powerful use of plugins is to load a [[WoaS::Help::Macros|macro]], or a set of macros, that will be available to all pages. The plugins directory also contains an Italian translation plug-in, though translation support is not yet fully capable in WoaS.\n\
\n\
You can share WoaS plugins as [[WoaS::Help::WSIF|WSIF]] files by exporting them.\n\
== External plugins\n\
A WoaS plugin is just Javascript code, unless you create a plugin whose name starts with \'@\'. Such plugins are made up of external file references and a specific notation to force the browser into a specific inclusion mode.\n\
\n\
Example:\n\
{{{path/to/mylib1.js = +*\n\
path/to/mylib2.js = @*}}}\n\
\n\
The first resource, {{{path/to/mylib1.js}}}, will be included as an inline Javascript (e.g. like source code inside a {{{\x3Cscript \x3E}}} tag), while the second, {{{path/to/mylib2.js}}}, will be included using an external ({{{\x3Cscript\x3E}}} tag with proper \'src\' attribute).\n\
=== Inclusion operators\n\
There are two inclusion operators which are valid for resource definitions:\n\
* *+* - which leads to inline inclusion\n\
* *@* - which leads to external inclusion\n\
The word which directly follows such inclusion operator can be any of the following supported tokens:\n\
* *{{{*}}}* catch-all, which means any browser/engine\n\
* *ie* Internet Explorer\n\
* *firefox* Mozilla Firefox (-)\n\
* *opera* Opera Internet Explorer\n\
* *safari* Apple Safari (-)\n\
* *chrome* Google Chrome\n\
* *gecko* Gecko engine (Mozilla)\n\
* *webkit* WebKit engine (Safari/Chrome)\n\
* *presto* Presto engine (Opera)\n\
* *trident* Trident engine (Internet Explorer)\n\
*Note: * tokens marked with (-) do not support version matching\n\
\n\
Now let\'s consider a more complex example:\n\
\n\
{{{path/to/mylib1.js = +* @gecko(1.9+)\n\
path/to/mylib2.js = @*}}}\n\
\n\
{{{path/to/mylib1.js}}} will be loaded as inline for all browsers except those which have a Gecko engine with version 1.9 or above (i.e. Firefox 3.6 and above).\n\
',
'Aliases are replaceable shortcuts used in wiki links.\n\
==Example\n\
If /$JD/ is defined in [[WoaS::Aliases]] as {{{John Doe}}} then the link {{{[[$JD::Bio]]}}} will be converted to {{{[[John Doe::Bio]]}}} when rendered by WoaS.\n\
\n\
Aliases can turn out to be particularly useful to shorten typing of long page names.\n\
== Add an alias\n\
An alias is added by editing the [[WoaS::Aliases]] reserved page and adding an alias line to the page. For example:\n\
\n\
{{{$JD    John Doe}}}\n\
\n\
*$JD* is the alias, which will be replaced when found in wiki page title references, and /"John Doe"/ is the text which will replace *$JD*. You can specify any part of page titles in aliases, like namespaces or page prefixes/suffixes.\n\
',
'\x3Cfieldset id="S10522" class="woas_input_wrap"\x3E\x3Clegend\x3EExisting pages\x3C/legend\x3E\\\n\
\x3Clabel\x3E\x3Cinput type="radio" id="woas_import_ask" name="woas_import_overwrite" onclick="woas.importer.i_overwrite=3" checked="checked"\x3EAsk before overwrite\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="radio" id="woas_import_erase" name="woas_import_overwrite" onclick="woas.importer.i_overwrite=0"\x3EErase all user pages before import process\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="radio" id="woas_import_ignore" name="woas_import_overwrite" onclick="woas.importer.i_overwrite=1"\x3EIgnore\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="radio" id="woas_import_overwrite" name="woas_import_overwrite" onclick="woas.importer.i_overwrite=2"\x3EOverwrite\x3C/label\x3E\n\
\x3C/fieldset\x3E\\\n\
\x3Cfieldset id="S4030" class="woas_input_wrap"\x3E\x3Clegend\x3ESecurity\x3C/legend\x3E\\\n\
\x3Cdiv class="woas_input_wrap_left"\x3E/If you don\'t trust the pages you are importing you may want to disable imported Javascript, macros, and special WoaS pages until you can review their content./\x3C/div\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_import_comment_js" onclick="woas.importer.i_comment_js=this.checked"\x3EComment Javascript tags\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_import_comment_macros" onclick="woas.importer.i_comment_macros=this.checked"\x3EComment macro definition/call\x3C/label\x3E\n\
\x3Clabel\x3E\x3Cinput type="checkbox" id="woas_cb_import_no_woas" onclick="woas.importer.i_no_woas=this.checked"\x3EDo not import [[WoaS::]] namespace pages ([[WoaS::Hotkeys|hotkeys]], [[WoaS::Plugins|plugins]], and [[WoaS::Aliases|aliases]])\x3C/label\x3E\n\
\x3C/fieldset\x3E\n\
',
'Web pages can be included in a page as embedded HTML objects or in HTML iframes.\n\
\x3C\x3C\x3Cwoas.note: Some pages may not render correctly depending on how they\'re coded. Embedding more than one web page in a wiki page will cause the final embedded web page to steal the focus when the page is loaded, so it\'s recommended to have only one per page.\x3E\x3E\x3E\n\
== Embed a web page as an object\n\
This method makes the embedded web page become a seamless part of the page.\n\
* *Embed a local HTML file as an object:*\x3Cbr\x3E\x3Cbr\x3E\n\
** \x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PATH with the full path to the HTML file you wish to include, and changing the width and height to suit your taste:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cobject data="PATH" style="width:100%; height:630px;"\x3EFile not found.\x3C/object\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo embed a local HTML file in a page.\x3C/div\x3E\x3Cbr\x3E\n\
*** For example, this command embeds the {{{/Work/MyProject.html}}} file into a page as an object:\x3Cbr\x3E\x3Cbr\x3E{{{\n\
\x3Cobject data="/Work/MyProject.html" style="width:100%; height:630px;"\x3EFile not found.\x3C/object\x3E\n\
}}}\x3Cbr\x3E\x3Cbr\x3E\n\
* *Embed a remote URL as an object:*\x3Cbr\x3E\x3Cbr\x3E\n\
** \x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing URL with the URL of the page you wish to include, and changing the width and height to suit your taste:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Cobject data="URL" style="width:100%; height:630px;"\x3EURL not found.\x3C/object\x3E\x3C\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo embed an external URL in a page.\x3C/div\x3E\x3Cbr\x3E\n\
*** For example, this command embeds the WoaS official website at {{{http://stickwiki.sf.net/}}} into a page as an object:\x3Cbr\x3E\x3Cbr\x3E{{{\n\
\x3Cobject data="http://stickwiki.sf.net/" style="width:100%; height:630px;"\x3EURL not found.\x3C/object\x3E\n\
}}}\n\
== Embed a web page in an HTML iframe\n\
This method creates a frame around the embedded web page. The code shown below is for a plain frame, but you can style the iframe further by adding a border, changing the border style to dotted, dashed, solid, double, groove, ridge, inset, or outset, changing the border width to whatever thickness you like, and the border color to whatever color you like.\n\
* *Embed a local HTML file in an iframe:*\x3Cbr\x3E\x3Cbr\x3E\n\
** \x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PATH with the full path to HTML file you wish to include, and changing the width and height to suit your taste:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Ciframe height="400" width="100%" height:630px; src="PATH"\x3E\x3C/iframe\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo include a local HTML file in a wiki page.\x3C/div\x3E\x3Cbr\x3E\n\
*** For example, this command embeds the {{{/Work/MyProject.html}}} file into a page in an iframe:\x3Cbr\x3E\x3Cbr\x3E{{{\n\
\x3Ciframe height="400" width="100%" height:630px; src="/Work/MyProject.html"\x3E\x3C/iframe\x3E\n\
}}}\x3Cbr\x3E\x3Cbr\x3E\n\
* *Embed a remote URL in an iframe:*\x3Cbr\x3E\x3Cbr\x3E\n\
** \x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing URL with the URL of the page you wish to include, and changing the width and height to suit your taste:\x3C/div\x3E\x3Cbr\x3E{{{\n\
\x3Ciframe height="400" width="100%" height:630px; src="URL"\x3E\x3C/iframe\x3E\n\
}}}\x3Cbr\x3E\x3Cdiv class="woas_help_text"\x3ETo include a web page in a wiki page.\x3C/div\x3E\x3Cbr\x3E\n\
*** For example, this command embeds the WoaS official website at {{{http://stickwiki.sf.net/}}} into a page in an iframe:\x3Cbr\x3E\x3Cbr\x3E{{{\n\
\x3Ciframe height="400" width="100%" height:630px; src="http://stickwiki.sf.net/"\x3E\x3C/iframe\x3E\n\
}}}\n\
',
'You can include a text file in a page by placing it inside of an HTML iframe.\n\
\n\
\x3Cdiv class="woas_help_text"\x3EUse this code in a page, replacing PATH with the full path to the file:\x3C/div\x3E\n\
{{{\n\
\x3Ciframe height="400" width="100%" src="file:///PATH"\x3E\x3C/iframe\x3E\n\
}}}\n\
\x3Cdiv class="woas_help_text"\x3ETo include a text file in the page inside an iFrame.\x3C/div\x3E\n\
== Examples\n\
* *Linux example:*\x3Cbr\x3E\x3Cbr\x3E{{{\n\
\x3Ciframe height="400" width="100%" src="file:///home/username/Desktop/file.txt"\x3E\x3C/iframe\x3E\n\
}}}\x3Cbr\x3E\n\
* *Windows example:*\x3Cbr\x3E\x3Cbr\x3E{{{\n\
\x3Ciframe height="400" width="100%" src="file:///C:/Users/Username/Documents/file.txt"\x3E\x3C/iframe\x3E\n\
}}}\n\
',
'The look and feel of the wiki is determined by the default CSS definitions in the [[WoaS::CSS::Core]] page. Although the [[WoaS::CSS::Core]] page cannot be edited, the definitions can be copied and used as a foundation for customizing the wiki in any of the ways described in the [[WoaS::Help::CSS|CSS]] page.\n\
',
'The [[WoaS::CSS::Custom]] page can be used to add new CSS definitions to the wiki or to override the definitions in the [[WoaS::CSS::Core]] page by copying them to the [[WoaS::CSS::Custom]] page and [[WoaS::Help::CSS|customizing them]] to suit your taste.\n\
',
'The [[Locked::]] page displays a list of all pages that have been locked with [[WoaS::Help::Security|AES encryption]].\n\
',
'The [[WoaS::CSS::Boot]] page cannot be edited, and contains the CSS definitions that determine how the wiki will look and feel while it is loading.\n\
',
'The first time you save a change to Wiki on a Stick, your browser will ask for permission to save data to the disk. This is normal and necessary for the wiki to make changes to itself. You can give permission each time or make the setting permanent.\n\
\n\
You will find the *Help* icon in the navigation bar on every page in this wiki. When you click on it, it will open a pop-up window with either the [[WoaS::Help::Index]] page or a specific help page associated with the page you currently have open.\n\
== Contents\n\
/These pages will open in the [[WoaS::Help::Index|Help system]]./\n\
\n\
[[Include::WoaS::Help::]]\n\
',
'The [[Special::Orphaned Pages]] page displays a listing of all pages that no other pages [[WoaS::Help::Links|link to]].\n\
',
'The [[Special::Recent Changes]] page is an optional wiki feature that keeps track of [[WoaS::Help::Edit a page|changed pages]] when enabled.\n\
* When the feature is not enabled, the page displays a notice stating that the last modified timestamp storage is disabled in Special::Options.\n\
* When the feature is enabled, the page displays a list of links to pages that have been changed followed by the date and time of the most recent change.\n\
== Enable tracking of page changes\n\
# Click the *Advanced* icon in the navigation bar.\n\
# Click the [[Special::Options]] link in the *Advanced features* section of the page.\n\
# Click the box next to the /Store and display last modified timestamp/ option in the *Saving* section of the page to place a check mark in the box.\n\
# Click the *Save options* button to save the change.\n\
',
'This wiki offers two ways to search for content:\n\
* The search box in the menu which uses the [[WoaS::Template::Search]] page as a template.\n\
* The [[Special::Search]] page, which you can get to by clicking the *Advanced* icon in the menu and looking in the *Pages* section.\n\
It is recommended that you do one-word searches to avoid lengthy searches that pop up unresponsive script warnings. Also, type only the exact search term(s) into the box without surrounding the term(s) with quotes or using other characters unless the content you\'re searching for contains them.\n\
\n\
The results display links to pages with the search term in their title followed by links to pages that contain the search term, the number of hits, and the the highlighted search term surrounded by content.\n\
== Add a search box or search link to a page\n\
The search box in the menu can be deleted by editing the menu and removing the {{{[[Include::WoaS::Template::Search]]}}} line. If you would like a search box in another page in the wiki, add the line you removed from the menu where you would like the box to appear in the page. To add a link to the [[Special::Search]] page to any page in the wiki, insert {{{[[Special::Search]]}}} anywhere in the page.\n\
',
'The [[Special::All Pages]] page displays a list of all [[WoaS::Help::Create a page|user-created pages]].\n\
',
'The [[Tagged::]] page displays a list of all pages that have been [[WoaS::Help::Tags|tagged]].\n\
',
'The [[Unlocked::]] page displays a list of all plain pages (pages that have not been locked with [[WoaS::Help::Security|AES encryption]]).\n\
',
'The [[Untagged::]] page displays a list of all pages that have not been [[WoaS::Help::Tags|tagged]].\n\
',
'The [[Special::Export]] page provides an interface for exporting the wiki content into multiple linked XHTML files.\n\
\x3C\x3C\x3Cwoas.note: WoaS code generates valid XHTML, but if the WoaS author has included invalid XHTML code within a wiki page, WoaS will not attempt to reform it. /Garbage in, garbage out!/\x3E\x3E\x3E\n\
== Paths\n\
=== Directory for XHTML files\n\
The exported XHTML files will be placed into the /export/ subdirectory in the directory the wiki is in by default. You can specify a different directory.\n\
=== Directory for embedded pictures\n\
The exported embedded pictures (if any) will be placed into the /export/ subdirectory in the directory the wiki is in by default. You can specify a different directory. If there are no embedded pictures, this setting will be ignored.\n\
\x3C\x3C\x3Cwoas.note: In both cases, unless you are using a Mozilla browser, the destination directory must exist.\x3E\x3E\x3E\n\
== Extension for generated XHTML files\n\
The default extension for generated XHTML files is /html/. You can specify a different extension.\n\
=== Name the main page /index/ (plus file extension above)\n\
If this choice is enabled, the main page will be named /index/ with the extension specified above, otherwise it will be named /main_page/, also with the extension specified above.\n\
\n\
For example, if the default extension is used and this option is enabled, the main page would be named /index.html/\n\
=== Apply UNIX-style normalization to generated filenames (all lowercase letters; non-alphanumeric characters replaced with underscores)\n\
If this option is enabled, all exported file names will be in lower case with all spaces and non-alphanumeric characters replaced by underscores, otherwise the files will be named according to the page name.\n\
== Custom page scripts\n\
===Do not export Javascript\n\
If selected any scripts embedded in the page to be exported will not be run before exporting the page, nor will they be included in the exported XHTML file.\n\
===Export Javascript as-is\n\
If selected any scripts embedded in the page to be exported will be included in the parsed, exported XHTML file in the same position they were found in the WoaS page. They will not be run before exporting.\n\
===Run before exporting but do not export the Javascript\n\
If selected any scripts embedded in the page to be exported will be run before exporting the parsed, exported XHTML file. This is only useful if a script on the page affects the parsed output -- a syntax highlighter, for example -- and it is desired that the exported pages do not require the viewer to have Javascript enabled in their browser as the scripts themselves will not be exported.\n\
== Other options\n\
===META author (optional)\n\
If a name is in this box it will be used as the content of an HTML author meta tag inserted into each exported HTML page. If the box is empty, the HTML author meta tag will not be inserted into any of the exported HTML pages.\n\
===Export CSS into shared file\n\
If selected a CSS stylesheet will be generated for the entire file set and imported by each exported XHTML file; if not selected the full CSS will be included within each XHTML file.\n\
===Export menus\n\
If selected any menu (including any sub-menu) that would show for a particular WoaS page will also be rendered in the output XHTML file; if not selected only the main page area wil be rendered and exported\n\
',
'The [[Special::Import]] page provides an interface for importing the contents of a current or earlier version of the wiki from an .html source file (back to v0.9.6B). Certain options are only available if the context allows.\n\
== Source\n\
Click the *Browse...* button to select the wiki file to import.\n\
===Import configuration (except WSIF datasource settings)\n\
Imports all the settings from the [[WoaS::Help::Special::Options|Special::Options]] page in the source file into the destination file.\n\
\x3C\x3C\x3Cwoas.note: The settings in the /[[WoaS::Help::Special::Options#WSIF Settings|WSIF settings]]/ section of the /Special::Options/ page will not be imported.\x3E\x3E\x3E\n\
===Import content\n\
Imports these pages from the source file:\n\
* Any user-created pages.\n\
* [[Main Page]]\n\
* [[::Menu]]\n\
and also these pages unless /Do not import WoaS:: namespace pages/ is selected:\n\
* [[WoaS::Aliases]]\n\
* [[WoaS::Hotkeys]]\n\
* [[WoaS::Plugins]]\n\
===Import custom CSS\n\
Imports the [[WoaS::CSS::Custom]] page from the source file, overwriting the same page in the destination file. CSS rules from older releases of the wiki may not work properly in the current version; see [[WoaS::Help::CSS#Import CSS rules into your wiki|Import CSS rules]].\n\
\n\
Importing custom CSS and configuration from a current WoaS version, while not importing content, is a good way to copy a custom wiki set-up.\n\
== Existing pages\n\
===Erase all user pages before import process\n\
Erases all user-created pages before importing content into the destination file. The import interface will pop up two confirmation boxes to verify that you\'re sure you want to erase the pages.\n\
===Ignore\n\
Prevents the import interface from overwriting existing pages, allowing only  new pages to be imported into the destination file.\n\
===Overwrite\n\
Gives the import interface blanket permission to overwrite existing pages in the destination file.\n\
===Ask before overwrite\n\
Forces the import interface to ask your permission to overwrite individual pages in the destination file.\n\
== Security\n\
===Comment Javascript tags\n\
Inserts /disabled_/ into any script tags in the pages that are imported into the destination file so that scripts will not run.\n\
\n\
Example script tag:\n\
{{{\n\
\x3Cscript type="text/javascript"\x3Ealert("This is an example alert!");\x3C/script\x3E\n\
}}}\n\
Example disabled script tag:\n\
{{{\n\
\x3Cdisabled_script type="text/javascript"\x3Ealert("This is an example alert!");\x3C/disabled_script\x3E\n\
}}}\n\
===Comment macro definition/call\n\
Inserts /Macro disabled/ into any macro definitions or macro calls in the pages that are imported into the destination file so that macros will not run.\n\
\n\
Example macro call:\n\
{{{\n\
\x3C\x3C\x3Cwoas.include: My Page\x3E\x3E\x3E\n\
}}}\n\
Example disabled macro call:\n\
{{{\n\
\x3C\x3C\x3C Macro disabled\n\
woas.include: My Page\x3E\x3E\x3E\n\
}}}\n\
===Do not import WoaS:: [[WoaS::Help::Namespaces|namespace]] pages ([[WoaS::Help::Aliases|aliases]], [[WoaS::Help::Hotkeys|hotkeys]], and [[WoaS::Help::Plugins|plugins]])\n\
Does not allow import of pages listed.\n\
',
'The [[Special::Backlinks]] page, which is displayed by clicking the [[Special::Backlinks|Backlinks]] link in the menu, displays a list of all pages linking to the current page.\n\
',
'The menu can contain links to pages, wiki interfaces, and shortcuts to custom functions you create. You can [[WoaS::Help::Edit the menu|edit the menu]] and sub-menus by clicking the edit icon located in its bottom right corner. Sub-menus belong to [[WoaS::Help::Namespaces|Namespaces]] and are discussed in the [[WoaS::Help::Namespaces#Namespace sub-menu|sub-menu]] section there.\n\
\n\
If the wiki is erased the menu contents are slightly reduced, with less often used links removed; these links are still accessible from the Special::[[WoaS::Help::Special::Advanced|Advanced]] page. These are the default contents of the menu with the pages linked briefly explained, with links to more detailed help pages, when available:\n\
* /Main Page/ - The main page of the wiki.\n\
* /[[WoaS::Help::Special::Options|Options]]/ - The Options page where basic configuration settings can be set.\n\
* /WoaS History/ - A  page detailing the history of this wiki; this page is deleted if the wiki is erased.\n\
\n\
* /WoaS::Help/ - A page listing all the pages in the WoaS::Help::[[WoaS::Help::Namespaces|namespace]]; opens in the main wiki.\n\
* /[[WoaS::Help::Aliases|WoaS::Aliases]]/ - A page that allows you to create replaceable shortcuts used in wiki links.\n\
* /[[WoaS::Help::Hotkeys|WoaS::Hotkeys]]/ - A page that allows you to create key bindings for hotkeys and access keys.\n\
* /[[WoaS::Help::Plugins|WoaS::Plugins]]/ - A page that allows you to create, import, and manage plug-ins.\n\
\n\
* /[[WoaS::Help::Special::All Pages|Special::All Pages]]/ - A page that displays a list of all user-created pages.\n\
* /[[WoaS::Help::Go to a page|Go to...]]/ - An interface for typing in the title of a page to go to (defaults to the current page).\n\
* /[[WoaS::Help::Special::Recent Changes|Recent Changes]]/ - An optional wiki feature that keeps track of changed pages when enabled.\n\
\n\
* /[[WoaS::Help::Special::Backlinks|Backlinks]]/ - A page that displays a list of pages linking to the current page.\n\
* /[[WoaS::Help::Create a page|New Page]]/ - An interface for creating a new page.\n\
* /[[WoaS::Help::Duplicate a page|Duplicate Page]]/ - An interface for creating a duplicate of a page (defaults to the current page).\n\
* /[[WoaS::Help::Delete a page|Delete Page]]/ - An interface for deleting a page (defaults to the current page).\n\
\n\
* /[[WoaS::Help::Erase all pages|Erase Wiki]]/ - An interface for erasing the wiki and restoring it to its default state.\n\
\n\
* /[[WoaS::Help::Special::Search|Search box]]/ - A direct-entry interface for entering a search term to search all the user-created pages in the wiki.\n\
',
'= By /Special::/ action link/command\n\
# Access [[Special::Duplicate Page]] from a [[WoaS::Help::Links|link]] (e.g. from the Special::[[WoaS::Help::Special::Advanced|Advanced]] page, default [[WoaS::Help::Menu|menu]], or user page) or by using the Special::[[WoaS::Help::Go to a page|Go to]] command.\n\
# You\'ll be offered the title of the current page with /(duplicate)/ added at the end; this can be replaced with the title of your choice.\n\
# Accept by pressing the /OK/ button, or cancel by pressing the /Cancel/ button.\n\
# When the page is duplicated, you\'ll be on the new page you just created.\n\
',
'= By /Special::/ action link/command\n\
# Access [[Special::Go to]] from a [[WoaS::Help::Links|link]] (e.g. from the Special::[[WoaS::Help::Special::Advanced|Advanced]] page, default [[WoaS::Help::Menu|menu]] (Go to...), or user page).\n\
# You\'ll be offered the title of the current page.\n\
# Type in the name of the page you wish to go to.\n\
# Accept by pressing the /OK/ button, or cancel by pressing the /Cancel/ button.\n\
# If the page exists, you\'ll be taken to it. If it doesn\'t exist, and isn\'t in a [[WoaS::Help::Namespaces#Reserved namespaces|reserved namespace]], the [[WoaS::Help::Create a page|page creation interface]] will open and offer to help you to create the page.\n\
',
'[[Special::TOC]]\n\
= Improvements made\n\
== Operation\n\
* The Help system has been improved in capability, style, and content (the last in large part thanks to Little Girl). Every Help page now opens in the Help system, except the [[WoaS::Help::|namespace listing]] and the [[WoaS::Help]] information page. This allows the Help system to become an active guide to using the wiki, as links to the main wiki clicked from within a Help page opens in the main wiki (as they always did). Help page links can now target page sections in the Help system and also in the main wiki.\n\
\n\
* Namespace listings have been, IMHO, greatly improved in styling, and also in capability. The [[Special::All Pages]] listing (renamed for consistency with the other special pages) now also lists no-namespace pages in a fold (they used to overwhelm the listing in large files). I intend to add the capability to select a listing style within the page link in the new project. The [[Special::Orphaned Pages]] code has been rewritten so that it completes in the square-root of the time it used to take (important in a wiki with hundreds of pages), and the [[Tagged::]] listing now allows some really powerful listings if, like me, you make extensive use of tags. The [[Image::]] listing is also -- again IMHO -- much improved and has styles added for those who want complete control of the presentation.\n\
\\\n\
== Layout\n\
* I have spent a huge number of hours updating the CSS and HTML layout and checking it across popular browsers, with generally pleasing results. Layout now stays consistent across most text size and zoom changes. (For some reason Opera seems to make all the text bigger than other browsers, but this is easily changed with the \'zoom\' control.)\n\
\n\
* The layout now adjusts to very long page titles.\n\
\n\
* Links to headings will now appear below the header instead of behind it. This has removed the need for a semi-transparent header. The linking system has also been fixed/improved, allowing a section to be linked to when loading the file ({{{woas.html?my page#section}}}) and not creating browser history when clicked in the TOC. The code has been refactored so that legal section heading are used internally that also have a much smaller chance of conflicting within a page. These may be made more accessible in the new project as either the usual form or the internal form (e.g.: #S123) can now be used.\n\
** The file load section doesn\'t work in all browsers yet as the \'#\' is interpreted as a section to jump to, putting it behind the header. In the new project this will not be an issue, so I have not spent much time trying to fix it. I am willing to fix this if it is a felt need.\n\
\n\
* The TOC code has been rewritten to allow a lot more control of presentation and is now foldable. I don\'t want a numbered TOC so the current CSS reflects that fact; if there is a demand I will create plugins for various views, including the old numbering (I have created the code for this in testing, including full section numbering; e.g. 2.1.9). The new code allows the TOC to start at any heading level without errors.\n\
\n\
* I have changed the order of the navigation icons a little to be more consistent (mostly, it stops the /Help/ icon moving around when switching to /edit/ mode), and updated & minimized the icons. The lock icon view has been reversed as it was very confusing; they now reflect what will be done when clicked, just like the other icons, not the status of the page. The CSS styling for a locked page has also been changed to a red border on locked pages and can be easily modified through custom CSS, including returning the original display.\x3Cbr\x3E\x3Cbr\x3EI am rewriting the code so icons can be easily moved to any position (mostly for Little Girl & [[http://bookonastick.wordpress.com|BoaS]]\'s sake), though the new project will make this unnecessary because the layout will come from layout pages that are rendered on load.\n\
\n\
* The editor has been improved in that it now acts as a single page (if there is enough screen layout available), removing the double scrollbars that used to appear. It works well across all browsers, including IE6. I was going to do the same with the view layout (and developed code to do so, allowing fixed layout in all browsers) but have decided to wait and do it in the new project. I also need to decide whether to add image capabilities to IE6&7 in the new project as I have code written that can do so. Would be interested in feedback on this.\n\
\\\n\
== Parsing\n\
* Most URLs, like https://example.com/page?hi#there, will be recognized and kept from being seen as text markup (try this page in 0.12.0). If /Automatically convert URLs to hyperlinks/ is turned on in the [[Special::Options#User Interface|User Interface]] section of [[Special::Options]], and the URL is recognized (http, https, file, ftp) then the URL will also be automatically turned into an external wiki link. This doesn\'t fix UNIX paths, but as long as the path doesn\'t have a leading slash, it should be rendered correctly: my/path/t. In my new project I want to add syntax, consistent with Creole 1, that stops the next character (or perhaps next syntax block; e.g: \'{|\') from being interpreted as markup. (There are many other ways to accomplish this as well, like recognizing backslash escapes within the line.)\n\
\n\
* In-line syntax for text styling -- italics, bold, underline -- all work the same in that they cannot cross lines of text (in 0.12.0 underline would work across lines). Other than that I have now returned to the original parsing rules for 0.12.0 with the exception that bold markup can start after "/" and "\\"; I can\'t see why this existed other than for file path display (where it fails in many instances). Italics cannot start after a colon (\':\'), presumably also to protect file paths; this is standard behaviour in 0.12.0. I am considering protecting file paths in my new project in much the same way as I have now protected URLs (by removing them from parsing).\n\
\\\n\
= Bug Fixes\n\
/See my *[[http://stickwiki.svn.sourceforge.net/viewvc/stickwiki/branches/pvhl/fix/log.txt|log.txt]]* in SVN for a fuller list of fixes. The file, as it was when I uploaded this file, is also [[log.txt|included in this wiki]], so you can get an idea of the changes made./\n\
== Major\n\
* Fixed the file corruption that happened in WoaS.0.12.0 when using Java for saving (Chrome, Safari, Opera).\n\
* Fixed Firefox 7+ breaking file selection\n\
\\\n\
== Minor\n\
* many parser spacing fixes\n\
\n\
* Many changes to fix layout issues across browsers in Windows, including IE 6&7. Layout is now consistent at all text sizes and zoom levels in all major browsers (in Windows; I have done only limited testing for Linux, and none at all for Mac). I have been able to test early versions of IE and Firefox, but have no ability (or real desire) to test early versions of Chrome, Opera, and Safari. /I also had not realized how many load|save related WoaS features only work in Firefox! I have code to make image embedding work in IE, but adding such capabilities to the other browsers will have to be limited and based either on a new Java system, or HTML 5./\n\
\n\
* Most history and navigation icon errors have been removed.\n\
',
'WHILE THE CODE IN \'FIX\' IS BEING UPDATED/MERGED IT MAY NOT ALWAYS BE WORKING AS FOUND.\n\
IT IS NOT BEING TESTED MUCH DURING THIS PROCESS AND COULD OCCASIONALLY BE BROKEN.\n\
\n\
That said, I\'m actually trying to make sure that only working \'fix\' code is uploaded, especially for the woas-fix[.min].html files; these will not always be the same as the multi-file code for that reason.\n\
\n\
I am near to having a finished, fixed 0.12.0. to upload. I simply don\'t have the time to commit changes piece by piece. If anyone really wants to see it later I\'ll consider sending them my git development repository (what a mess!)\n\
\n\
Changes since Revision pvhl-2317 (git: 3d939c7)\n\
\n\
(needing to archive my work in an incomplete though working state; export probably isn\'t working right yet)\n\
\n\
* enable import of wsif files with Windows EOL (just in case)\n\
* complete fix of page locking (incl. button: forgot I hadn\'t finished refactoring; sorry)\n\
* fix incorrect \'index\' status I added to multiple page wsif saves\n\
* add woas_print_title CSS class and title to print window\n\
* fix print window reuse in some browsers\n\
* close help and print windows on exit/reload (doesn\'t work in Opera)\n\
* remove my macro.parse function (was being tested)\n\
* fix page rename function failing in some browsers (!)\n\
* adjust header height for long titles (better fix coming but this one works OK)\n\
* move page export lists from core.js to export.js; only used there and want to change them\n\
* fix search button (template) moving to next line some text resizes\n\
* fix (IE) Help window error when waiting for JS permission\n\
* fix WoaS::Template::Info script error (mea culpa) and minor content changes\n\
* fix bold/italic/underline crossing line endings when in a list\n\
* revert bold/italic/underline parsing to (mostly) conform to 0.12.0 and recent marker changes\n\
* fix my URL autolink generation\n\
* undeprecate Tags:: namespace\n\
* fix section jump error I introduced with last CSS change\n\
* move search string check\n\
* add some comments to i18n.js\n\
* index: revert info macro change and add some export CSS for later\n\
* some macro, css, and autolink fixes\n\
* add loading capability to i18n and update some strings\n\
* fix exported scripts (were being exported with br tags added for every newline!)\n\
* final name change of \'WoaS::Template::Transclusion Example\' to \'WoaS::Help::Template transclusion::Example\'\n\
* quick hack to fix page export; works with/without menus and allows for custom export CSS\n\
* add export version to new TOC code\n\
* change Print function to use .woas_print and add CSS to WoaS::CSS::Core (allows customization)\n\
* refactor Special::Export page layout (to match others) and associated help page\n\
* rearrange Special::Advanced page and add some missing links (may need Help pages for File:: and Image::)\n\
* fix woas._reserved_rx (broken RegExp was testing titles incorrectly -  e.g. [[A WoaS::... tested true)\n\
* add ability to jump to fieldset headings in import/export pages\n\
* modify macro code so block macros can work correctly; refactor macro help page\n\
* improve script disabling and search result layout\n\
* rename \'Transclusion\' help page to \'Template transclusion\' and update associated help pages\n\
* fix errors in java saving (one mine from refactoring code; one original; now works in Windows Chrome & Opera)\n\
* disallow " in wiki links (they break the link and aren\'t allowed by code)\n\
* replace all occurrences of JavaScript with Javascript to avoid namespace confusion\n\
* refactor Javascript:: namespace to allow title declaration, and update help page\n\
* update Import and Options help pages\n\
* allow import of CSS only from HTML file (CSS & Config allows import of wiki setup without content)\n\
* fix failure to update display when importing configuration and improve import reporting\n\
* dim debug button instead of removing\n\
* moved woas.refresh_menu_area (was now woas.refresh_menu) to woas.ui.refresh_menu\n\
* fix failure to remove wait cursor on import of debug_mode = true\n\
* refactor erase_wiki to remove edge-case failure and simplify\n\
* change name of \'WoaS::Template::Example::Transclusion\' to \'WoaS::Template::Transclusion Example\'\n\
* add some missing help pages from Little Girl\n\
* help pages open in help system except WoaS::Help (an intro) and WoaS::Help::\n\
* changed name of Recentchanges to \'Recent Changes\'\n\
* \'WoaS History\' page is deleted on erase (as an unneeded user page) and not imported (could be older)\n\
* some changes to menu and erased menu\n\
* numerous CSS tweaks incl. reducing nowiki styles to single declarations\n\
* TOC refactored to fix parse errors and allow greater control; added roll-up to TOC\n\
* submenus are now a single menu\n\
* change to how heading anchors are created\n\
* capture enter key in password pages to avoid having to click the button\n\
* improve image pages and image gallery (an incomplete beginning; more tomorrow I hope)\n\
* fix loading of page reference at start-up\n\
* adjust the colour scheme\n\
* fix go_to code to handle page section links\n\
* multiple fixes to allow my current fix-wip code to work with ie6/7 and be left with WoaS\n\
* more work on using CSS classes to control layout\n\
* change d$.clone to woas.clone, add d$.toggle_class with optional resize\n\
* disable menu edit and Options save buttons, and remove some options when read-only\n\
* add icon lockout code for new display system, and a ui state discovery system\n\
* fix all the array printouts; failed if length was 1; also removed base16 array encoding as no shorter\n\
* fix \'Lock::xxx\' being saved as current page to open\n\
* fix some woas history issues, especially with options and locking/unlocking\n\
* add Special::Options information concerning what is about to happen\n\
* fix broken FF7 path access, and general rewrite of file load\n\
* update Special::Import and Special::Export Help pages\n\
* delete WoaS::Template::Button as no longer needed and remove it and WoaS::Template::Info from code\n\
* add official macro for info box and use in Help Pages; will expand function later\n\
* Asthetic adjustment to Recent Changes\n\
* Changes to breadcrumbs display: improve asthetics and fix issue with ::Menu & Namespace listings\n\
* Changes to Tagged:: listing to improve capability\n\
* Refactor of listing code to simplify and add no-namespace folding\n\
* Refactor of orphan pages code ( Order(n) instead of O(n*n) )\n\
* Redesign and tuning of HTML, CSS, and control code for main layout\n\
* New Help pop-up code; works in all browsers (even IE6)\n\
* Allow import of encrypted images (partial fix; will revisit later)\n\
* Redesign of Special::Import and Special::ImportWSIF and associated functions\n\
* add separate settings for import and importWSIF and fix import of old settings\n\
* disable plist use until various broken commit and autosave code is fixed\n\
* use reFwdSlash instead of new regexp each time\n\
* change wsif_ds check to whole name instead of length\n\
* Updated legacy.js to include call information (with help from Little Girl)\n\
* Redesign of Special::ExportWSIF and associated Help page; others to follow\n\
* Redesign of Special::Options and associated CSS and Help page\n\
* Fix 2 small errors including broken list CSS\n\
* Bring Help window forward if hidden\n\
* disable WSIF blob saving as only Gecko can do it and others corrupt file\n\
* add \'wsif.type: index\' to allow safe loading/saving of exported multi-file WSIF\n\
* allow recursive load of WSIF files so multi-file index file can be used\n\
* hack fix of path in WSIF data source; stop file being corrupted for bad path\n\
* fix backspace/erase causing page back action when in textbox\n\
* reload file if erase wiki failed\n\
* add new help pages and help page updates from Little Girl\n\
* change default setting for config import to safer setting\n\
* add new page menu link options\n\
* small changes to various page layouts\n\
* fix export and edit for submenus and fix up _add_namespace_menu\n\
* change nowiki_multiline parsing to match macro parsing rules and break-out function\n\
* modify how hotkey accesses restricted word \'goto\'\n\
* improve show/hide/toggle functions\n\
* remove visibility attribute from WoaS (display is sufficient in all cases)\n\
* update i18n strings (mostly Little Girl\'s work)\n\
* hide \'make woas read only\' in read only woas\n\
* fix macro backup functionality\n\
* add macro.parse ability\n\
* fix macro regexp and related issues (follow rules similar to nowiki and work better with block syntax)\n\
* refactor woas.log for better efficiency\n\
* fix legacy log function I broke; replace remaining log() calls in code\n\
* disable debug history log\n\
* remove h1 from no script; corrupted by IE on save\n\
* fix logo width in IE8+\n\
* modify woas.include macro to stop page listing header display\n\
* allow menu for earlier namespace to show up if no ns menu found\n\
* change namespace listing to use divs instead of spans\n\
* fix Special:: namespace listing and associated issues\n\
* add option to start with console closed and clean up the html a bit\n\
* change debug/log function so it can be turned on/off dynamically\n\
* add all pages option and filename to Special::ExportWSIF\n\
* add fix header/menu options and rearrange things a bit\n\
* fix woas.browser.firefox_new test\n\
* fix included pages shown in Special::Orphans (found by Michele1995)\n\
* fix tweak var replacement in mk\n\
* stop WoaS History being exported in user page WSIF files\n\
* correct incorrect number of pages in index.wsif\n\
* some base64 rearrangement\n\
* error in load_mode spelling\n\
* fix file read \'off by one error\' (extra byte was read for binary); also fixes html comment issue (--\x3E)\n\
* fix base64 encoding (was failing for images with NULL)\n\
* fix macro error - no returned value bug\n\
* fix bad Firefox identification\n\
* fix bug I introduced: missing menu update after edit (found by Michele1995)\n\
* fix bug I introduced: missing namespace links after edit (found by Michele1995)\n\
* redo last fix to correct error introduced (broke img tags; found by Michele1995)\n\
* redo fix for block html to allow tags to break across lines + simplify\n\
* changes to stop \'tag found\' warning during build\n\
* slight clean up; simplify/clarify place_holder function by adding place_holder_dnl\n\
* fix bad export CSS\n\
* redo nowiki to fix insanity of my new code\n\
* partial fix for export html problems\n\
* fix export html CSS background\n\
* remove width settings from woas.htm (broke layout in some browsers)\n\
* fix external disposition wsif import failure (found by tomas)\n\
* changes to allow more custom help pages\n\
* slight Special::Options rearrangement\n\
* add (currently inactive) code to remove blank line between same-type lists\n\
* simplify heading parser\n\
* add sort_tags configuration option\n\
* add auto_links configuration option and tidy option page slightly\n\
* fix import disable issues for IE\n\
* fix macro dynamic_nl issues\n\
* fix italic/underline parsing issues and add autolinks\n\
* fix sorting in tag listing\n\
* fix hash location issues introduced earlier\n\
* refix some previous fixes to remove side-effects\n\
* fix transclusion loop\n\
* fix double-quotes in title\n\
* fix plug-in name check when creating\n\
* fix bad lock message\n\
* initial spacing fix -- same issues as official (a better fix coming)\n\
* redo fix for replacing html tag(s)\n\
* some more history.backstack fixes missed earlier\n\
* refix css export\n\
* fix broken search results display and adjust its CSS\n\
* fix newline before alpha list bug and tiny change to list code\n\
* stop all WoaS::CSS pages being exported (Boot and namespace were)\n\
* fix incorrect display of exported pages because of help pages being exported twice\n\
* fix bad file_mode in export.js (ASCII -\x3E ASCII_TEXT)\n\
* refactored woas.parser._render_wiki_link (to test an idea and for a coming plugin)\n\
* update aes module closures to recommended practice (removes jslint warning)\n\
* fix extra line after tables\n\
* optimize list parsing code\n\
* mostly parser module rearrangement and relocation of some parse code to parser.js\n\
* fix empty namespace listing\n\
* change \'header\' to \'heading\' where heading is intended (avoid confusion with wsif headers)\n\
* fix double calling of nav icon update for certain instances\n\
* don\'t ask to create menu link if already in menu (needs rewrite for namespace menus)\n\
* more page delete fixes including deleting page that is not current but in history\n\
* mostly more ghost page fixes\n\
* move ghost page disabling to disable_edit()\n\
* clear log div at start-up (fixes a Firefox bug)\n\
* improve page saving (removes unneeded save of editor text)\n\
* modified sprintf function\n\
* tiny history log format change\n\
* stop some block HTML markup from having a br tag added\n\
* fix ruler bug (eats multiple preceding \\n); also simplifies code\n\
* changes to allow html comments in nowiki and macro output\n\
* changed all marker formats; also fixes potential bug if marker followed by a numeral\n\
* parser.dry made more efficient and simpler; combined macro expansion into pre_parse\n\
* change place_holder to simplify code; now pushes to array and returns marker text\n\
* minor change to tag display (moved a space)\n\
* minor change to menu updating for import wiki\n\
\n\
==Changes made before move to fix-wip\n\
\n\
Revision pvhl-2317 (fix branch)\n\
* fix non-breaking tags display issue\n\
\n\
Revision pvhl-2314\n\
* fix broken Italian language plugin and update design (adding a change to i18n\n\
  during lock fix was a reminder that translations will break using the current\n\
  \'overwrite everything\' system; rewrote the Italian language plugin and added\n\
  a \'pvhl.notes\' file on improving language support in WoaS)\n\
\n\
Revision pvhl-2313\n\
* hack incorrect lock icon display\n\
\n\
Revision pvhl-2312\n\
* macroTagThis and reformat\n\
* restore print page no browsing warnings\n\
* added Plugins help page to index\n\
* slight grammatical change\n\
* slight ui.js changes\n\
\n\
Revision pvhl-2309\n\
* fix broken nowiki (was failing after heading; better fix to come)\n\
* fix potential edge-case failure in placeholder.\n\
* slight cleanup to woas._raw_preformatted\n\
* added CSS3 rule to core CSS to break unbreakable lines\n\
\n\
Revision pvhl-2308\n\
* fix nowiki class spelling I thought I\'d already fixed\n\
* update single files\n\
\n\
Revision pvhl-2291\n\
* some changes to the About page to explain this version\n\
* add php files that will be used to create single-file (not finished)\n\
* stop \'#\' being used in page titles (found by jufooo)\n\
* change to log display: closed on loading\n\
* fix wrong mts display (reported by Winterblood)\n\
\n\
Revision pvhl-2289\n\
* fix Chrome file corruption issues\n\
* fix edit_override to allow edit of WoaS namespace\n\
* quick changes (hack) to remove cancelled new page from menu\n\
* slight change to menu to allow better addition placement\n\
* fix logbox scroll position after save and improve function\n\
* small formatting change for readability\n\
* some minor comment additions\n\
\n\
Revision pvhl-2288\n\
* hack for cumulative save issues\n\
* fix no-load mode error when mode = 0\n\
* fix new page history (still some edge case issues)\n\
* fix commit bug in unused code :(\n\
\n\
Revision pvhl-2287\n\
* fix history so back/forward buttons work\n\
* fix help back button (not working in FF/IE)\n\
\n\
Revision pvhl-2286\n\
* syntax fixes found by Little Girl\n\
* syntax fixes found by PVHL\n\
* fixed up deprecated go_to() & go_back\n\
* minor documentation clarifications\n\
',
'= Examples\n\
\n\
== Introduction\n\
\n\
The AMASE development kit includes examples to help AMASE developers understand the structure of AMASE and provide a starting point for custom AMASE applications.  AMASE examples can be found in the \x3Cem\x3Eexamples\x3C/em\x3E directory of the development kit.\n\
\n\
To setup and run the AMASE examples, create a Java project using your preferred development environment.  For a feature rich free IDE, we suggest \x3Ca href="http://www.netbeans.org"\x3ENetbeans\x3C/a\x3E but any development environment will work.  Make sure you have a Java development kit version 7 or higher installed.  If you are unfamiliar with Java development, it is highly recommended that you first familiarize yourself with Java through the many tutorials and references available online.  AMASE uses advanced Java features and object-oriented principles that require thorough knowledge of Java.\n\
\n\
            \n\
== Building a simple AMASE Application\n\
                \n\
AMASE applications consist of a set of plugins designated through a configuration file. AMASE plugins are java classes that extend the base class \x3Ccode\x3Eavtas.amase.AmasePlugin\x3C/code\x3E. AMASE plugins can,\n\
\n\
* access configuration data, \n\
* communicate with other plugins via events, \n\
* provide GUI and menu items to the user\n\
* perform modeling, data collections, and many other AMASE functions\n\
\n\
The simplest AMASE application is shown below.  This tutorial will explain elements of an AMASE application through this example. \n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/sample_app.png\' /\x3E\n\
\x3C/div\x3E\n\
\n\
This application has a small set of plugins to enable loading scenarios and displaying information to the user.  The application can be run using the SampleApp batch file in the examples folder of the run folder in the AMASE development kit. To run this application on the command line, one can also execute the following command (assuming the current directory is the AMASE development kit root folder):\n\
\n\
\x3Cdiv class="code_sample"\x3E\n\
java -cp dist/* avtas.app.Application --config config/examples/SamplePlugin\n\
\x3C/div\x3E\n\
\n\
The application constructed of a small set of AMASE plugins.  In the command above, note that the \x3Ccode\x3E--config\x3C/code\x3E parameter points to the directory \x3Ccode\x3ESamplePlugin\x3C/code\x3E.  AMASE looks in the config directory for a file named \x3Ccode\x3EPlugins.xml"\x3C/code\x3E.  The Plugins.xml file for this application contains the following:\n\
\n\
{{{\n\
\x3CPlugins\x3E\n\
        \n\
    \x3CPlugin Class="avtas.amase.scenario.ScenarioManager"/\x3E      \n\
\n\
    \x3CPlugin Class="avtas.amase.window.WindowService"/\x3E\n\
\n\
    \x3CPlugin Class="avtas.amase.scenario.ScenarioEventViewer"/\x3E\n\
\n\
    \x3CPlugin Class="avtas.amase.ui.IconManager"/\x3E\n\
    \n\
    \x3CPlugin Class="amase.examples.SamplePlugin"\x3E\n\
        \x3CAnyParameter\x3Evalue\x3C/AnyParameter\x3E\n\
    \x3C/Plugin\x3E\n\
        \n\
\x3C/Plugins\x3E\n\
}}}\n\
\n\
Plugins are loaded according to the fully qualified class name of the plugin.  A compiled java class with the given name must be on the java classpath.  Plugin entries can contain additional parameter information as XML children of the \x3Ccode\x3EPlugin\x3C/code\x3E entry.  This information is passed to the plugin through the \x3Ccode\x3EaddedToApplication\x3C/code\x3E method that is called after the plugin is constructed.\n\
\n\
Several plugins interact to make the application work.  For instance, the ScenarioManager enables loading scenario files through the \x3Ccode\x3EFile -\x3E Open Scenario\x3C/code\x3E menu. Events read from the scenario file are published to the entire application via the [[Plugin::EventManager| Event Manager]] system.  The [[Plugin::WindowService| Window service]] provides the main windows inside which plugins can place GUI elements.  The [[Plugin::IconManager| IconManager]] enables the user to specify custom icons for entities in AMASE.  Finally, the SamplePlugin entry is what we will use to explore AMASE plugins and capabilities in this example.\n\
\n\
The SamplePlugin provides a GUI to user that includes a button for every aircraft loaded in the scenario.  Aircraft are specified in scenario files using the \x3Ca href="lmcp/detail.html#CMASI_datatype_AirVehicleConfiguration" target="blank"\x3EAirVehicleConfiguration\x3C/a\x3E object.  When the ScenarioManager reads an AirVehicleConfiguration from the input file, it publishes it out to all other listeners that are registered with the [[Plugin::EventManager | Event Manager]].  The SamplePlugin listens for these and other events through its \x3Ccode\x3EeventOccurred\x3C/code\x3E method.\n\
\n\
{{{\n\
   public void eventOccurred(Object event) {\n\
        if (event instanceof SessionStatus) {\n\
            SessionStatus ss = (SessionStatus) event;\n\
            System.out.println("Time: " + ss.getScenarioTime() + ", state: " + ss.getState());\n\
        }\n\
        else if (event instanceof AirVehicleConfiguration) {\n\
            AirVehicleConfiguration avc = (AirVehicleConfiguration) event;\n\
            System.out.println("aircraft " + avc.getVehicleID() + " added to scenario.");\n\
            addAircraftButton(avc);\n\
        }\n\
        else if (event instanceof ScenarioEvent) {\n\
            ScenarioEvent scenario = (ScenarioEvent) event;\n\
            System.out.println("scenario " + scenario.getSourceFile().getName() + " loaded.");\n\
            buttonPanel.removeAll();\n\
        }\n\
    }\n\
}}}\n\
\n\
The event management system is a core feature of AMASE, and is the primary way in which plugins interact.  Note that in this class, we handle SessionStatus, AirVehicleConfiguration, and ScenarioEvent objects.  All other types of events are simply ignored.  Using the java \x3Ccode\x3Einstanceof\x3C/code\x3E check is a convenient way to test for a particular type of message.\n\
\n\
',
'= LMCP - The Lightweight Message Construction Protocol (LMCP)\n\
\n\
\n\
\n\
== Introduction\n\
The Lightweight Message Construction Protocol (LMCP) is a standard that serves two purposes.  First, it defines a structure for common data types and a process for serializing objects based on those types.  Secondly, it defines a method for encapsulating objects for transmission between applications.  This specification describes the structure of data types, without specifying how applications implement the handling instantiations of those data types. Applications that implement this specification can send and receive objects regardless of the operating system, platform, or programming language used.  LMCP is a simple and extensible specification, so it can be implemented without a central runtime, proprietary libraries, or with the complexity of other protocols such as HLA and DIS. \n\
\n\
This system offers several advantages to the end-user, including\n\
* A design independent of language, platform, and transport protocol.\n\
* Object-oriented approach through structured data types, including support for null objects.\n\
* A high level of customizability through user-defined data models.\n\
* Support for variable length arrays and nested objects.\n\
* Simple and open design, free of proprietary code and requiring no runtime infrastructure or special libraries.\n\
\n\
LMCP also defines the structure of a message.  A message is a LMCP object which is encapsulated with header and footer items to enable communication of LMCP objects between applications. LMCP allows developers to create custom data types easily through a message data model (MDM).  Custom classes can be created for a given MDM through automatic code generation or other means to recognize and handle messages. \n\
\n\
==	Data Model\n\
\n\
LMCP implements an object-oriented data model.  The data model describes all of the LMCP data types that are valid for a given LMCP network. An LMCP data type is a structure of other valid LMCP data types, similar to how a class is defined in an object-oriented computer language.  Only objects that are reserved by this standard or declared in the same Message Data Model (MDM) may be members of a data type. Section 5 describes how a data model is created.  \n\
\n\
===	Primitive Types\n\
LMCP defines several primitive data types that can be used by LMCP objects, as shown in Table 1.  These types are the basis for forming meaningful data structures that are described by the MDM.\n\
\n\
=== Arrays\n\
Data types defined in an MDM may contain array data in the form of fixed or variable length arrays.  An array data type is a list of data of the same type.  Arrays can contain only one type of data. Arrays may contain null values if the type is not a primitive data type (i.e. a structured data type). \n\
LMCP reserves a special array data type, \u201cstring\u201d.  A string is a variable length array of char (see Table 1).  \n\
\n\
\n\
{|\n\
|+ *Table 1. Predefined LMCP Data Types*\n\
| *Type* || *Size (bytes)* || *Definition and Limits*\n\
| bool	   || 1	    ||  True (1) or false (0)\n\
| byte	   || 1	    ||  0 to 255\n\
| char	   || 1	    ||  byte limits, values according to ASCII table\n\
| real64   || 8	    ||  2.2e-308 to 1.8e308\n\
| real32   || 4	    ||  1.2e-38 to 3.4e38\n\
| int64	   || 8	    ||  -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807\n\
| int32	   || 4	    ||  -2,147,483,648 to 2,147,483,647\n\
| int16	   || 2     ||  -32,768 to 32,767\n\
| uint32   || 4	    ||  0 to 4,294,967,295\n\
| uint16   || 2	    ||  0 to 65,535\n\
| string   || variable || a variable length array of char types\n\
|}\n\
\n\
\n\
=== Structured Data Types\n\
The MDM is a listing of the structured data types.  A structured data type is analogous to an object-oriented class.  Structured types can contain primitives, arrays, or other structured data types.  LMCP supports inheritance of data types. See Section 5 for information on how to define data types.\n\
\n\
=== Object Serialization\n\
An LMCP object (an instance of an LMCP structured data type) is serialized by placing byte representation of all object contents into a buffer.  A serialized LMCP object shall be readable by any other application that implements this standard.  De-serialization of object bytes shall yield an object of identical content of the source object.  Serialization occurs in declaration order; all members of an LMCP object are converted to bytes and placed in a byte array in the order that they are declared by the MDM.\n\
\n\
== More Information\n\
LMCP is maintained by AFRL/RQQD.  Contact the branch ([[Contact Info]]) to learn more ',
'= AMASE Architecture\n\
\n\
AMASE is built on a modular application architecture.  Several components sit on top of a platform that allows plugins to intercommunicate and access common data sources.  The AMASE application framework is shown in Figure 2.  AMASE plugins are Java classes that are added to the AMASE application (also known as the Context).  Once added, the plugins are informed of other plugins that are in the system, and are notified when new plugins are added.  Plugins often listen for the addition of other plugins because there is a client-server relationship between the two.  For example, a plugin may present the user with a graphical interface (GUI).  The Window Manager looks for plugins that offer a GUI and loads it into a window.\n\
Plugins can access some resources through a static  reference.  Commonly used items, such as the event manager (described later) or the current scenario state are maintained in static objects. This style of application design allows for easy integration of plugins and management of resources, while minimizing complexity, since static references can be accessed from anywhere in the application.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/amase_architecture.png\' height="300" width="400" /\x3E\n\
\x3Cp class="caption"\x3EAMASE Architecture\x3C/p\x3E\n\
\x3C/div\x3E\n\
 \n\
\n\
\n\
== Event Management\n\
\n\
AMASE is an event driven simulation.  Events are published and consumed by plugins that are loaded in the application.  AMASE events can be any type of Java object, but are most often LMCP messages.  Most AMASE plugins listen for LMCP events and perform necessary logic based on the type of event.\n\
\n\
\n\
\n\
',
'= AMASE Development\n\
\n\
AMASE is designed to be a toolkit from which many different applications can be developed.  Using a model similar to open source, AMASE is distributed to users within the DoD and DoD partner organizations in order to foster a wide community of AMASE developers.  Within the bounds of contracts and regulations, AMASE code should be shared with all interested parties.  Enhancements and bug fixes should also be shared with the current maintainer of the AMASE development kit, currently AFRL/RQQD.\n\
\n\
\x3Cdiv class="woas_note"\x3E\n\
If you are unfamiliar with Java development, it is highly recommended that you first familiarize yourself with Java through the many tutorials and references available online.  AMASE uses advanced Java features and object-oriented principles that require thorough knowledge of Java.\n\
\x3C/div\x3E\n\
 \n\
== AMASE Development Kit\n\
\n\
AMASE is delivered as a development kit.  End users can access all of the source files used to develop AMASE. Addditional library dependencies can be found in the \x3Ccode\x3Elib\x3C/code\x3E folder of the development kit.\n\
\n\
{|\n\
|+  AMASE Development Kit Source Structure\n\
| *Folder*	|| *Description*\n\
|Core*	        || Support classes and utilities for use in AMASE-based applications\n\
|Amase*	        || AMASE models and related code to support CMASI objects\n\
|Amase 3D	|| Classes to enable Worldwind-based visualization\n\
|Automation Tools ||	Classes that enable automation/autonomy and mission planning (experimental)\n\
|Aero Tools	|| Higher-fidelity flight modeling\n\
|ELVIS	        || User interface elements to support the development of Engineering-Level Vehicle Interface Systems\n\
|Setup Tool	|| Classes used to build the AMASE setup tool application\n\
|example*	|| Example AMASE plugins and support code\n\
|}\n\
\n\
(Only items with an * are available in the OpenAMASE version of AMASE)\n\
\n\
\n\
== Code Documentation\n\
\n\
The AMASE development kit is documented throughout using the javadoc tool.  The \x3Ca href="./api/index.html" target="_blank"\x3EAPI Reference\x3C/a\x3E is always a good place to look for information on how a particular AMASE component functions.\n\
\n\
== Core Application Tools\n\
\n\
AMASE Core tools are designed to be standalone components.  Developers can uses the Core source to develop any Java application.  The application structure and utilities available to developers through the AMASE core package can significantly reduce the time required to develop an application.  The AMASE application infrastructure, event management, and window management can be leveraged to create a simple plugin-based application very rapidly, as is shown in the [[SimpleExampleApp|Simple Example Application]].\n\
',
'= IconManager\n\
',
'= EventManager\n\
',
'= WindowService\n\
',
'= An Example Application\n\
\n\
\n\
The AMASE development kit includes examples to help AMASE developers understand the structure of AMASE and provide a starting point for custom AMASE applications.  AMASE examples can be found in the \x3Cem\x3Eexamples\x3C/em\x3E directory of the development kit.\n\
\n\
To setup and run the AMASE examples, create a Java project using your preferred development environment.  For a feature rich free IDE, we suggest \x3Ca href="http://www.netbeans.org"\x3ENetbeans\x3C/a\x3E but any development environment will work.  Make sure you have a Java development kit version 7 or higher installed.  If you are unfamiliar with Java development, it is highly recommended that you first familiarize yourself with Java through the many tutorials and references available online.  AMASE uses advanced Java features and object-oriented principles that require thorough knowledge of Java.\n\
\n\
            \n\
== Building a Simple AMASE Application\n\
                \n\
AMASE applications consist of a set of plugins designated through a configuration file. AMASE plugins are java classes that extend the base class \x3Ccode\x3Eavtas.amase.AmasePlugin\x3C/code\x3E. AMASE plugins can,\n\
\n\
* access configuration data, \n\
* communicate with other plugins via events, \n\
* provide GUI and menu items to the user\n\
* perform modeling, data collections, and many other AMASE functions\n\
\n\
The simplest AMASE application is shown below.  This tutorial will explain elements of an AMASE application through this example. \n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/sample_app.png\' /\x3E\n\
\x3C/div\x3E\n\
\n\
This application has a small set of plugins to enable loading scenarios and displaying information to the user.  The application can be run using the SampleApp batch file in the examples folder of the run folder in the AMASE development kit. To run this application on the command line, one can also execute the following command (assuming the current directory is the AMASE development kit root folder):\n\
\n\
\x3Cdiv class="code_sample"\x3E\n\
java -cp dist/* avtas.app.Application --config config/examples/SamplePlugin\n\
\x3C/div\x3E\n\
\n\
The application constructed of a small set of AMASE plugins.  In the command above, note that the \x3Ccode\x3E--config\x3C/code\x3E parameter points to the directory \x3Ccode\x3ESamplePlugin\x3C/code\x3E.  AMASE looks in the config directory for a file named \x3Ccode\x3EPlugins.xml"\x3C/code\x3E.  The Plugins.xml file for this application contains the following:\n\
\n\
{{{\n\
\x3CPlugins\x3E\n\
        \n\
    \x3CPlugin Class="avtas.amase.scenario.ScenarioManager"/\x3E      \n\
\n\
    \x3CPlugin Class="avtas.amase.window.WindowService"/\x3E\n\
\n\
    \x3CPlugin Class="avtas.amase.scenario.ScenarioEventViewer"/\x3E\n\
\n\
    \x3CPlugin Class="avtas.amase.ui.IconManager"/\x3E\n\
    \n\
    \x3CPlugin Class="amase.examples.SamplePlugin"\x3E\n\
        \x3CAnyParameter\x3Evalue\x3C/AnyParameter\x3E\n\
    \x3C/Plugin\x3E\n\
        \n\
\x3C/Plugins\x3E\n\
}}}\n\
\n\
Plugins are loaded according to the fully qualified class name of the plugin.  A compiled java class with the given name must be on the java classpath.  Plugin entries can contain additional parameter information as XML children of the \x3Ccode\x3EPlugin\x3C/code\x3E entry.  \n\
\n\
Several plugins interact to make the application work.  For instance, the ScenarioManager enables loading scenario files through the \x3Ccode\x3EFile -\x3E Open Scenario\x3C/code\x3E menu. Events read from the scenario file are published to the entire application via the [[Plugin::EventManager| Event Manager]] system.  The [[Plugin::WindowService| Window service]] provides the main windows inside which plugins can place GUI elements.  The [[Plugin::IconManager| IconManager]] enables the user to specify custom icons for entities in AMASE.  Finally, the SamplePlugin entry is what we will use to explore AMASE plugins and capabilities in this example.\n\
\n\
== Life Cycle of a Plugin\n\
\n\
When \x3Ccode\x3Eavtas.app.Application\x3C/code\x3E starts, it loads the plugins from the configuration ("Plugins.xml") file and calls the \x3Ccode\x3EaddedToApplication\x3C/code\x3E method to initialize the plugin.  Note that xml data is passed to this method. In \x3Ccode\x3ESamplePlugin\x3C/code\x3E, this method simply echos the contents to show the user how the data is passed.  When other plugins are loaded, the \x3Ccode\x3EapplicationPeerAdded()\x3C/code\x3E method is called for every peer.  For any plugins that were added previously, \x3Ccode\x3EapplicationPeerAdded()\x3C/code\x3E is also called.  \n\
\n\
If a peer is removed,  \x3Ccode\x3EapplicationPeerRemoved()\x3C/code\x3E is called when the peer is removed from the \x3Cem\x3Econtext\x3C/em\x3E.  The context is simply a container where plugins are stored and are notified of changes in the application.\n\
\n\
A plugin (optionally) provides items to the application for the purposes of user interaction.  The if method \x3Ccode\x3EgetGui()\x3C/code\x3E returns a Java component to provide a GUI display.  This is typically a JPanel that contains user interface widgets, but can be any kind of Java component.  The method \x3Ccode\x3EgetMenus()\x3C/code\x3E enables the user to add menus to the application menubar.  Note that the plugin \x3Ccode\x3EWindowService\x3C/code\x3E provides the functionality to manage menus and GUIs.  the method \x3Ccode\x3EgetSettingsPanel\x3C/code\x3E can be overridden to provide a panel with settings tools.  The method \x3Ccode\x3EgetIcon\x3C/code\x3E returns a custom icon for the plugin.  Note that all of the GUI related methods are optional.  Default implementations are provided in the base \x3Ccode\x3EAmasePlugin\x3C/code\x3E class that return null. Simply override each method to return something meaningful.\n\
\n\
If a plugin is removed from the application, then \x3Ccode\x3EremovedFromApplication\x3C/code\x3E is called.\n\
\n\
When the application is shutdown, two plugin methods are involved.  the method \x3Ccode\x3ErequestShutdown\x3C/code\x3E is first called on all loaded plugins.  This returns true by default.  If overridden, then shutdown logic can be performed here.  For example, a plugin can ask the user if data should be saved.  If the answer is no, then the plugin should return true (meaning it is okay to continue with shutdown). if the answer is "yes", then a dialog can be presented to allow the user to select a file.  Any reply of "false" to this method will prevent the application from shutting down.  Once the shutdown request is complete, the \x3Ccode\x3Eshutdown\x3C/code\x3E method is called, allowing plugins to perform final shutdown logic.  Once this process begins, there is is no way to prevent the application from shutting down.\n\
\n\
\n\
== Application Events\n\
\n\
\n\
The SamplePlugin provides a GUI to user that includes a button for every aircraft loaded in the scenario.  Aircraft are specified in scenario files using the \x3Ca href="lmcp/detail.html#CMASI_datatype_AirVehicleConfiguration" target="blank"\x3EAirVehicleConfiguration\x3C/a\x3E object.  When the ScenarioManager reads an AirVehicleConfiguration from the input file, it publishes it out to all other listeners that are registered with the [[Plugin::EventManager | Event Manager]].  The SamplePlugin listens for these and other events through its \x3Ccode\x3EeventOccurred\x3C/code\x3E method.\n\
\n\
{{{\n\
   public void eventOccurred(Object event) {\n\
        if (event instanceof SessionStatus) {\n\
            SessionStatus ss = (SessionStatus) event;\n\
            System.out.println("Time: " + ss.getScenarioTime() + ", state: " + ss.getState());\n\
        }\n\
        else if (event instanceof AirVehicleConfiguration) {\n\
            AirVehicleConfiguration avc = (AirVehicleConfiguration) event;\n\
            System.out.println("aircraft " + avc.getVehicleID() + " added to scenario.");\n\
            addAircraftButton(avc);\n\
        }\n\
        else if (event instanceof ScenarioEvent) {\n\
            ScenarioEvent scenario = (ScenarioEvent) event;\n\
            System.out.println("scenario " + scenario.getSourceFile().getName() + " loaded.");\n\
            buttonPanel.removeAll();\n\
        }\n\
    }\n\
}}}\n\
\n\
The event management system is a core feature of AMASE, and is the primary way in which plugins interact.  Note that in this class, we handle SessionStatus, AirVehicleConfiguration, and ScenarioEvent objects.  All other types of events are simply ignored.  Using the java \x3Ccode\x3Einstanceof\x3C/code\x3E check is a convenient way to test for a particular type of message.\n\
\n\
== Timer calls\n\
\n\
The SamplePlugin also includes two methods that are called by the [[timer]] during the simulation, \x3Ccode\x3Estep\x3C/code\x3E, and \x3Ccode\x3EtimerStateChanged\x3C/code\x3E.  These methods are optional, and provide the plugin with high-resolution timing signals.  The example application does not include a Timer facility, but if one were added, the plugin would print the time at every step, and print the change of the timer state when it started, paused, or rest.\n\
\n\
\n\
\n\
',
'= AMASE Timer\n\
\n\
The AMASE timer (\x3Ccode\x3Eavtas.amase.util.SimTimer\x3C/code\x3E) manages an internal simulation timer (\x3Ccode\x3Eavtas.app.Timer\x3C/code\x3E) to send high rate simulation step signals to clients.  It also manges the dispatch of [[CMASI]] SessionStatus messages.\n\
\n\
The AMASE timer registers plugins in the application.  \n\
\n\
== Direct Timer Access\n\
\n\
It is possible to access timing signals directly by manually adding a client to the \x3Ccode\x3Eavtas.app.Timer\x3C/code\x3E timer. Using the static method \x3Ccode\x3EgetDefaultTimer()\x3C/code\x3E, timer clients can be added to the default timing control in the application. Additionally, the application timer (or any other timer registered with the \x3Ccode\x3Eavtas.app.Timer\x3C/code\x3E class) can be controlled via public methods.  See the javadocs for more information.\n\
',
'= Scenario Files\n\
\n\
AMASE scenarios describe the data content that is used by AMASE to execute simulations.  AMASE scenario development involves the [[LMCP]] data interface, the [[Setup Tool]], and the [[CMASI]] data protocol.  \n\
\n\
Several examples are provided throughout this section.  It is recommended that the reader load and run these examples in AMASE.  Furthermore, experimentation is key to learning AMASE, as is true with most software products.  Users should use examples as a basis for more detailed scenario development\n\
\n\
== AMASE Scenario Files\n\
\n\
AMASE loads scenarios from files in the XML format.  XML is a human and machine readable text format that defines a tree structure of data.  AMASE includes a Setup Tool application that aids the user in developing scenarios using graphical interfaces, but it is recommended that the reader become familiar with XML syntax and structure, since hand-editing files is sometimes necessary.  This section describes the scenario file format using XML nomenclature and examples.  More information is available \x3Ca href="en.wikipedia.org/wiki/XML"\x3Ehere\x3C/a\x3E. \n\
\n\
AMASE scenario files typically follow the structure shown below.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/scenario_file_example.png\' /\x3E\n\
\x3C/div\x3E\n\
 \n\
\n\
Scenario files should start with the top-level name \u201cAMASE\u201d. The two major sections of a scenario file are the ScenarioData and ScenarioEventList, as shown in the figure.  Other sections can be included in a scenario file.  See later sections of this document for a discussion of custom sections in scenario files.\n\
The ScenarioData section of the scenario file includes metadata that describes the scenario being loaded.  This section is used by AMASE plugins.  In particular, the SimulationView section enables map displays to start with an appropriate view point for the scenario.  The ScenarioDuration parameter aids constructive simulation tools by denoting when a scenario is finished.  The Date field is used to denote when a scenario was last edited.\n\
\n\
The heart of an AMASE scenario is the ScenarioEventList.  This section includes all of the \u201cevents\u201d that are dispatched as part of the scenario definition.  The next section discusses scenario events.\n\
\n\
== Scenario Events\n\
\n\
Scenario events are XML representations of LMCP data objects.  LMCP is the native data language used by AMASE to send and receive events throughout the application and externally connected clients.  LMCP data objects can be serialized into XML according to the LMCP standard.  (See the LMCP Guide for more information on serializing LMCP objects as XML.)  AMASE uses the LMCP XML protocol as a basis for encoding events in AMASE scenario files.  AMASE deserializes these events at runtime and dispatches them to the simulation.  The figure below shows an example of a scenario event.  In this case, an AreaSearchTask (part of the CMASI message set) has been declared.  AMASE follows the LMCP XML definition to describe all of the fields of the object.  Additionally, a \u201cTime\u201d attribute is included to tell AMASE when to dispatch the event, in simulation time.  In this case, the event is dispatched at scenario load time (or 0.0 seconds).  If it were non-zero, the event would be dispatched by the simulation at the prescribed time.  \n\
Note that scenario events must be time-ordered to be properly dispatched.  For instance, if an event with a time of 10 seconds is listed later in the event list than an event with a time tag of 20 seconds, both events will be dispatched 20 seconds into the simulation.  An event that does not include a time attribute is assumed to have the same time value as the preceding event.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/event_example.png\' /\x3E\n\
\x3C/div\x3E\n\
\n\
== Working with the LMCP protocol\n\
\n\
Since scenario events are serialized LMCP objects, it is important to understand how AMASE uses LMCP to handle events.  LMCP uses a set of data definitions called MDMs.  Each MDM describes a set of data or \u201cmessages\u201d that can be serialized or deserialized by LMCP.  The primary MDMs used by AMASE are CMASI and ENTITIES.  These MDMs describe the data for defining entities (such as aircraft and ground vehicles), zones (such as Keep-In and Keep-Out boundaries), tasks for aircraft and ground entities to execute, and some support data such as Location2D and Location3D, which define geographic coordinates.  LMCP is built using the PackageMaker tool to include all of the MDMs that are needed for a given application.  In order for AMASE to read and write these objects, the LMCP build must include all of the data types that are described in the scenario files.  For instance, if a user needs to extend CMASI to include a new type of task, and then includes that task as part of a scenario file, then he/she must ensure that AMASE runs with the Java classes necessary to load all of the objects for that new MDM.\n\
\n\
== Example Scenarios\n\
\n\
Example scenarios are provided in the AMASE development kit in the \x3Ccode\x3Eexample scenarios\x3C/code\x3E directory.  \n\
\n\
===	Example 1 - Commanding an Aircraft\n\
\n\
In this example, a single aircraft is defined and commanded to fly a continuous route of waypoints.  At one of the waypoints, it\u2019s camera is commanded to stare at a geographic point. This example uses several aspects of the CMASI data protocol, including AirVehicleConfiguration, AirVehicleState, MissionCommand, and Waypoint.   In order for an aircraft to be properly loaded by AMASE, it must have an AirVehicleConfiguration, and AirVehicleState defined in the scenario.  The AirVehicleConfiguration declares the aircraft, and describes the payloads and dynamic constraints.  AirVehicleState declares an initial operating condition for the aircraft as well as any payloads that are on the aircraft. \n\
\n\
The aircraft in this example includes a simple EO camera that is mounted on a gimbal.  In CMASI, gimbals are defined using a GimbalConfiguration object.   The EO camera is defined using a CameraConfiguration.  The camera is \u201cadded\u201d to the gimbal by denoting the camera ID in the gimbal\u2019s list of contained sensors. \n\
The aircraft is initialized using an AirVehicleState object.  The AirVehicleState must include a valid speed value to operate correctly.  The aircraft model uses the declared AirVehicleState to initialize the kinematics properties.  Also, each payload (in this case a gimbal and a camera) is initialized with the declared state object.\n\
The AirVehicleConfiguration also includes a NominalFlightProfile and a list of alternate flight profiles.  These profiles are used by aircraft management tools and models to understand the flight properties of an aircraft.  The NominalFlight profile cannot be null, but the list of alternate profiles can be empty.  The nominal profile describes how the aircraft flies at its design condition. Alternative profiles can be used to describe other modes of flight, such as dash, climb, or descent. \n\
\n\
By examining the execution of the scenario in AMASE, one can see a number of features.  When the scenario starts, there is no route prescribed for the aircraft.  At 5 seconds into the simulation, a route appears.  The waypoints form a continuous loop, because the NextWaypoint field of the last waypoint is set to the ID of the first waypoint in the route.  The aircraft will fly this route until a new navigational action is commanded.  At the second waypoint, the gimbal is slewed to stare at a fixed location. The gimbal continues to stare at this point throughout the mission.  Note that as the aircraft banks, the footprint of the camera cannot remain fixed on the designated point due to the banking of the aircraft.  When the aircraft returns to level flight, the camera again fixes on the point.\n\
\n\
The route also makes use of the flight profiles defined for the aircraft.  The waypoints vary in altitude and speed along the route, and the model manages speed, altitude, and energy usage as it traverses the prescribed path.  Some of the waypoints are designated as \u201cTurnShort\u201d while others are \u201cTurnPast\u201d.  This governs when the aircraft begins its turn toward the next waypoint.\n\
  \n\
=== Example 2 - Loiters\n\
\n\
This example uses the aircraft from example 1, but commands loiter actions in place of waypoints.  The CMASI protocol supports three types of loiters \u2013 Circular, Figure Eight, and Racetrack.  This example shows each type of loiter executed for a fixed amount of time.  Instead of a CMASI MissionCommand, this example uses the CMASI defined VehicleActionCommand.  The loiters are added as actions to the command.  Each action is executed upon completion of the previous action.\n\
\n\
=== Example 3 - Zones and Tasks\n\
\n\
The CMASI data protocol includes representations of tasks and zones for the purposes of mission planning.  This example shows Keep-In and Keep-Out zones as well as examples of the three basic search tasks: point search, area search, and line search.  Zones and the AreaSearchTask both use the geometry system of CMASI.  The example shows Rectangle, Polygon, and Circle geometries.\n\
',
'= Setup Tool\n\
\n\
AMASE includes a facility for creating and editing scenario files graphically.  The AMASE setup tool features a 2D map similar to that in AMASE, and a set of graphical interfaces to edit different aspects of scenario files. \n\
\n\
The AMASE Setup Tool includes features to aid in graphically-based creation of AMASE scenarios.  The main components of the setup tool are shown below.  The map allows the user to create and manipulate objects graphically.  The event editor is used to set data in each of the scenario events created for the AMASE scenario.  The Object Toolbar is used in conjunction with the map to create new objects, and the scenario validator provides the user with feedback regarding errors in the scenario file.  There is also a text-based XML editor that allows the user to create or modify scenarios directly.  Although this is rarely used in creating basic scenarios, custom components might require scenario data that is easier to write by hand then to create custom plugins for the setup tool. \n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/setup/setup_tool.png\' /\x3E\n\
\x3C/div\x3E \n\
\n\
== The Map Component\n\
The map is used to quickly create and adjust graphical components in a scenario.  New objects can be created using the pop-up menu (right click) or by clicking on an item of interest in the Object Toolbar.  The behavior differs based on the object being created.  For instance, clicking on a polygonal search area puts the map into an editing mode that allows the user to click points, creating the outline.  Clicking on an aircraft icon gives the user the ability to place the aircraft using a single click.  Shapes can be manipulated interactively through dragging, selecting, or right-clicking to produce a pop-up menu. \n\
\n\
== Object Toolbar\n\
The Object Toolbar provides the user with the ability to quickly create basic CMASI-based events in AMASE scenarios.  Aircraft, entities (usually ground entities), Keep-in and keep-out zones, and search tasks can be created using the toolbar.  The toolbar interacts with the map to create basic, empty instances of scenario objects.  The user can then manipulate those objects using other setup tool components.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/setup/toolbar.png\' /\x3E\n\
\x3C/div\x3E \n\
\n\
== Event Editor\n\
\n\
The AMASE event editor gives the user direct access to fields that make up scenario events. The editor includes a display of all events in the scenario as well as a details panel for each scenario event.  The user can manipulate event order using the pop-up menu, add new events, or delete events.  All scenario events appear in the event editor, even if they originate in an LMCP series other than CMASI. (more on this later)  The Details Editor portion of the event editor also allows users to set fields for lists of objects.  For instance, the Event editor below shows a MissionCommand object in the details editor.  Right-clicking on the waypoint list brings up a set of fields that apply to all waypoints.  The user can set a value that is then applied to all points in the list.\n\
 \n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/setup/event_editor.png\' /\x3E\n\
\x3C/div\x3E \n\
\n\
Each event in the Event Editor has a time associated with it.  This is the time at which AMASE will dispatch the event.  Times can be set by right-clicking the event and setting the time value. Moving events up and down the list using drag and drop will also automatically change the time based on the times of events before and after the location in the list where the event is dropped.\n\
The Event Editor allows users to copy locations from the map and paste them into fields in the details editor.  Use the popup menu in the map to copy a CMASI Location2D or Location3D object, and then paste it into the appropriate field in the details area.  For example, a Location3D object is a valid entry for the \u201cPosition\u201d field of a CMASI AirVehicleState object.\n\
\n\
== Validator\n\
\n\
The AMASE scenario validator runs tests to check for common errors.  There is a set of tests included with AMASE that looks for the most common errors in scenarios.  This is a basic set and it is envisioned that developers will create additional tests to perform more in-depth scenario checking.  The validator is shown below.  Here, the validator finds that an AirVehicleConfiguration event has a maximum bank angle of zero.  This is a common error that causes aircraft to fly in straight lines despite commands to do otherwise.  A hyperlink to the event object allows the user to find and fix the problem quickly.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/setup/validator.png\' /\x3E\n\
\x3C/div\x3E \n\
\n\
== Scenario Properties\n\
\n\
AMASE [[Scenario Files]] also include a section on scenario properties.  Users can edit basic scenario properties using the menu selection Scenario \u2192 Edit Scenario Properties.  This brings up a dialog box for direct editing.  The scenario view (initial view for the 2D map) can be edited manually in this dialog, but it is more convenient to use the map\u2019s popup menu to set the scenario view.  This is done by right-clicking on the map and selecting Set Scenario View.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/setup/scenario_props_editor.png\' /\x3E\n\
\x3C/div\x3E \n\
 \n\
\n\
== XML Editing\n\
\n\
The Setup Tool includes an XML editor that allows users to directly edit any part of an AMASE scenario.  The editor includes syntax highlighting, and contextual menu support to format code, navigate the XML tree, and perform typical copy/paste actions.  The user can click items in the event editor (to the right in the figure) to select the XML content corresponding to the event.  When done editing, click the \u201cUpdate Scenario\u201d button to save the XML window content as an AMASE scenario.\n\
 \n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/setup/xml_editor.png\' /\x3E\n\
\x3C/div\x3E \n\
\n\
',
'= Running AMASE\n\
\n\
== Requirements\n\
\n\
Running AMASE requires a Java runtime version 7 or greater.  Java runtimes for several operating systems can be downloaded from \x3Ca href="http://java.com"\x3Ejava.com\x3C/a\x3E\n\
\n\
== AMASE Folder Structure\n\
\n\
AMASE is typically distributed as a zip archive.  This archive is platform independent and does not include an installer, so the end-user can store AMASE anywhere on his/her system.  AMASE and its associated programs are run through batch files (shell scripts on Linux and Mac) that are located in the run folder.  For example, to run the Windows version of AMASE, go to run -\x3E windows and execute one of the batch files.\n\
\n\
AMASE is distributed with three preconfigured applications (executed through batch files).  They are briefly described below:\n\
\n\
{|\n\
| AMASE         || This is the core application.  It includes models, user interfaces, and data management necessary to run AMASE scenarios.\n\
| Playback Tool || A version of AMASE that includes analysis tools to enable review of previously run AMASE sessions.  Output files from AMASE are read by  the Playback Tool.\n\
| Setup Tool    || This application includes tools to develop and edit AMASE scenario files.\n\
|}\n\
\n\
\n\
== AMASE User Interface\n\
\n\
The figure below shows AMASE when it is launched through the \u201cAMASE\u201d batch file.  To load a scenario, use the File-\x3E Open Scenario menu item.  Once the scenario is loaded, the status panel should show the aircraft that are loaded into the scenario and the map should zoom and pan if there is a view specified in the scenario file.  To run, pause, or change runtime speed, use the simulation controls that are located at the bottom of the window. \n\
\n\
The map can be panned and zoomed using intuitive mouse controls.  Holding the right mouse button and dragging will pan the map.  A right-click will bring up a pop-up menu.  Typical scroll actions (such as a mouse scroll wheel) will zoom the map in and out.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/main_window.png\' /\x3E\n\
\x3C/div\x3E\n\
\n\
Note that when a scenario is loaded, a status panel is produced for each aircraft in the scenario.  \n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/aircraft_status.png\' /\x3E\n\
\x3C/div\x3E\n\
\n\
\n\
At the bottom of the window, the simulation controls allow the user to start, pause, and reset AMASE.  A scenario file must be loaded for these controls to work.\n\
\n\
\x3Cdiv align="center"\x3E\n\
\x3Cimg src=\'images/sim_controls.png\' /\x3E\n\
\x3C/div\x3E\n\
\n\
== Connecting to the Simulation\n\
\n\
External applications may connect to the simulation on port 5555. the connection is set up as a TCP server. Clients should connect to the server by establishing a TCP socket on port 5555. Messages according to the CMASI MDM are sent and received over the socket.\n\
\n\
To check the status of the TCP connection, and to monitor traffic over the socket, use the menu item Server-\x3EShow Server Stats.\n\
\n\
The simulation publishes all messages that are read from the simulation setup file as well as continuously updating throughout the execution. Externally connected applications should expect AirVehicleState messages, SimStatus messages and TargetStatesReport messages at regular intervals, currently 2 Hz.\n\
\n\
== Changing Simulation Update Rates\n\
The simulation timer has two settings. The Frame Rate is the rate at which simulation components are informed of changes in the simulation time. The second setting controls the publication of SessionStatus message to the simulation and all connected clients.\n\
\n\
The Frame rate and the publish rate can be changed by choosing Simulation-\x3ETimer Options from the menu.\n\
\n\
== Saving Playback Files\n\
\n\
The simulation can save playback files by selecting File-\x3ESave Playback File from the menu. A playback file contains a list of all LMCP messages that were recorded during a simulation, excluding SessionStatus messages. Additionally, the playback file saves basic scenario information.\n\
\n\
== Collecting Analysis Reports\n\
\n\
AMASE and the Playback Tool come configured to produce and save analysis reports. These reports are in XML text format. Currently, the analysis package produces statistics on excursions from KeepInZones, incursions into KeepOutZones, Search area, line, and point coverage, and track target events (time acquired, time lost). The search coverage is presented graphically in the playback tool as well as providing data to the analysis report. All times are reported in seconds.\n\
\n\
To get analysis reports in AMASE or the Playback tool, choose Analysis-\x3EShowReport from the menu. This presents a window that contains the text-based analysis report for all events up to the current time. There are buttons in the window to save the output to a file, refresh the output if the simulation has updated since the last time the window was opened, or copy the XML to the system clipboard. \n\
\n\
== Running the Playback Tool\n\
\n\
The playback tool is run in a manner similar to the simulation. A slider bar allows the user to jump to a point in time, or the simulation controls can be used to playback the scenario in the same manner as the simulation. To open a playback file, choose File-\x3EOpen Playback File from the menu. Note that long scenarios produce large XML files. The playback tool may have a long delay when opening a file.\n\
\n\
== Headless Configuration\n\
\n\
AMASE can be run without a GUI by specifying the --config config/amase_headless option during startup.  The simulation real-time multiple can be set via --sim_rate n, which defaults to 1.0.  The scenario will immediately start playing. ',
'= Contact Info\n\
\n\
AFRL/RQQD\n\
2180 8th Street\n\
WPAFB, OH 45433\n\
AFRL/RQQD\n\
\n\
\x3Ca href="mailto:afrl.rq.opensource@us.af.mil"\x3Eafrl.rq.opensource@us.af.mil\x3C/a\x3E\n\
',
'= CMASI\n\
\n\
Mission planning for multiple UAV teams is an area of increasing interest, and is currently an important area of research for AFRL and its partner organizations.  UAV teams are often envisioned as performing multiple tasks such as searching an area, tracking targets, or relaying information1.  The objectives, constraints, and assets in a mission often create combinations that make it difficult for human operators to optimally allocate tasks and plan trajectories for multiple UAV team members.  To execute such missions, automation software can be employed to evaluate the objectives, constraints and resources in order to issue commands to individual UAVs.  To adequately allocate, plan, and execute cooperative missions, automation systems require information regarding the current mission context.  Descriptions of the mission tasks, airspace constraints, aircraft performance, and payload capabilities are among the information that must be provided to a mission automation service.\n\
\n\
To adequately command missions, automation tools need to know the capabilities and payloads of the aircraft involved. CMASI defines a number of data structures to encapsulate this information.  The AirVehicleConfiguration structure includes information regarding the kinematic capabilities of the aircraft, and contains a list of objects that describe the individual payload items that are on the aircraft.  The AirVehicleConfiguration type notifies the automation service of the existence of an individual aircraft.  During a CMASI session, all of the data required to characterize the aircraft and its capabilities is included in this single object.\n\
\n\
\x3Cimg src=\'images/cmasi_oo_design.png\' /\x3E\n\
\n\
Using an object-oriented approach allows payloads to be described in a way that is natural for a model of an aircraft. Payload objects are contained in a list that is contained in the AirVehicleConfiguration.  Leveraging the [[LMCP]] object-oriented design, the PayloadConfiguration structure is an abstract base type that is extended to create concrete types, as shown above. CMASI defines CameraConfiguration, GimbalConfiguration, and VideoStreamConfiguration as concrete payload types, all of which extend PayloadConfiguration.  These payloads define the characteristics necessary to command sensing tasks.  For instance, an aircraft may contain a gimbal.  The gimbal has limits in vertical and horizontal movement in both rate and position.  The gimbal may control other payloads, such as cameras.  A CameraConfiguration contains information regarding field-of-view, zoom capabilities, resolution, and spectrum (e.g. visible or infrared).  Although there is a small set of payload types declared by CMASI, the abstract PayloadConfiguration allows other MDMs to extend the base type to create additional payload types.  Automation systems use payload information to issue payload commands that are within the limits of the available resources. \n\
\n\
The kinematic capabilities of an aircraft are described through a list of FlightProfile structures.  The FlightProfile contains information regarding speed, maximum bank angle, fuel consumption, and climb (or descent) rate for that given condition.  A typical aircraft has more than one operating point, so the FlightProfile approach allows for a number of individual operating points to be specified.  For example, an AirVehicleConfiguration may include profiles for cruise, dash, loiter, and best-climb conditions. Using FlightProfiles allows for a broad description of the aircraft capabilities in a compact way. Automation systems can use the FlightProfiles to predict behavior and endurance  of an aircraft and ensure that commands are given within the operating envelope.\n\
		\n\
During a simulation each aircraft periodically updates its state information.  CMASI includes an AirVehicleState structure that provides this information.  The AirVehicleState includes position, orientation, and velocity data for the aircraft, as well as energy (fuel) remaining.  Information regarding each payload item aboard the aircraft is also included.  Like AirVehicleConfiguration, AirVehicleState includes a list of PayloadState items.  PayloadState is an abstract type, like PayloadConfiguration, which means there are concrete implementations for each type of payload.  Each payload state item reports the current state of its associated payload.  For example, a CameraState item reports a Camera\u2019s current field-of-view, and a GimbalState item reports the current azimuth and orientation of a gimbal. \n\
\n\
== Mission Tasks\n\
The key feature that differentiates  CMASI and from other UAV-related data interfaces is the definition of high-level tasks.  This concept was the impetus behind the creation of a new interface, rather than the adoption of an existing one such as STANAG 4586.  Mission tasks are high-level descriptions of objectives that are to be completed by one or more aircraft.  Since a primary use for CMASI is cooperative control, tasks are defined independent of the aircraft.  It is the role of the automation system to allocate tasks to the available aircraft based on the  task requirements and aircraft capabilities. \n\
\n\
A mission-level task is defined by an abstract base type called Task.  For reconnaissance missions, CMASI also defines another abstract type called SearchTask that extends Task.  Extending SearchTask are concrete types of AreaSearchTask, LineSearchTask, and PointSearchTask.  Each of these task types defines a request for imaging, but does so for a different type of geometry.  The SearchTask base type includes some information that is relevant to all of the concrete subtypes, including the type of requested wavelength band (e.g. visible or infrared), and the required ground-sample distance (i.e. the number of pixels required per unit length of ground).  Constraints such as these help to guide automation tools in setting altitude, field-of-view for adjustable cameras, gimbal angles, and aircraft speeds. Additionally, the search tasks also include a list of acceptable view-angles when performing the imaging.  This helps automation systems define angles of approach to fulfill each task objective.  \n\
Although CMASI focuses on reconnaissance and surveillance tasking, the use of a base Task structure allows other MDMs to implement additional types of tasks. \n\
\n\
== Zone Constraints\n\
\n\
Mission requirements often include areas where assigned aircraft are permitted or prohibited to fly.  CMASI defines different zone types to implement this.  Like other object-oriented constructs described above, zones are declared using a base type called AbstractZone.  An abstract zone includes a 2-D geometry that can be a polygon, circle, square, or any other shape that extends AbstractGeometry.  AbstractZone also includes altitude information defining the upper and lower bounds of the zone.  This creates a 3-D shape that is an extrusion of a 2-D shape from minimum to maximum altitude.  Two concrete types extend AbstractZone: KeepInZone, and KeepOutZone.  The KeepInZone declares where aircraft are allowed to fly while  KeepOutZone declares where aircraft are not allowed to fly.  KeepOutZone includes a field that declares the reason for the zone.  For example, a zone may be declared for regulatory reasons, it may be due to a the presence of a threat, or it may be declared in order to keep an aircraft outside of visual or acoustic range of a geographic point.  Both KeepInZone and KeepOutZone may be declared for a given set of aircraft or can be generalized for all aircraft.  The design of zones allows for the creation of complex geometries, since zones can be combined to create narrow corridors or highly restricted flight areas.\n\
\n\
== Aircraft Commands\n\
\n\
Automation systems need to issue commands in order to fulfill requests for tasking.  Commands vary in complexity based on the aircraft involved, the number and types of tasks, and the constraints considered.  Commands can encapsulate an entire mission, or do a simple one-time control of a payload item.  \n\
To facilitate the description of commands, it is necessary to introduce the concept of Actions.  An action is a specific task or activity that is performed by an aircraft.  Actions are separated into two categories, Navigational and Payload.  Navigational actions tell the aircraft where and/or how to fly.  Payload actions command a specific payload onboard the aircraft.  All actions extend a base Action type.  Payload actions extend the PayloadAction type. An example of an action is the GimbalStareAction, where a specified gimbal on-board an aircraft is commanded to slew towards the given geographic position.  This relies on the onboard system performing the appropriate computations to translate the request to slew the gimbal in azimuth and elevation so that attached sensors are aligned on the requested location.  Another example of an Action is the LoiterAction.  This is a command to put the aircraft into a loiter of the designated type.  \n\
Generally, actions are placed in action lists, which has the following rules. The list of actions is executed from start to end.  If an action requires a payload item that is currently executing a previous action, then that payload waits until the previous action is completed.  Otherwise, actions are executed in parallel.  For navigational actions, actions are executed in the same manner as a list of actions for a given payload (i.e. a LoiterAction is only executed after a previously declared LoiterAction is complete.)   \n\
CMASI provides two data structures for issuing a command to an aircraft.  First, the VehicleActionCommand, issues a list of actions to an aircraft.  The list is executed according to the rules described above.  Any previously executing actions are canceled if the new command contains actions that conflict with previously declared actions. VehicleActionCommand is typically used in situations where a payload command is required, such as steering a gimbal.  The second command type is the MissionCommand.  MissionCommands contain a list of waypoints for the aircraft to follow.  The waypoints are formed as a linked list, so waypoint lists can contain a number of closed loop plans or contingency points.  The command contains a field declaring which waypoint to start first.  \n\
\n\
Waypoints in CMASI are quite detailed.  Waypoints contain actions, which are stored in a list format.  When an aircraft reaches a waypoint, it executes the actions contained in the waypoint\u2019s action list in the same manner as receiving a VehicleActionCommand.  Waypoints designate the speed, climb rate, turn type (fly-past, or turn-short) as well as a contingency point that may be used by the aircraft in the case of an emergency (such as lost communications).  There are many existing UAV autopilots which cannot perform all of the functionality described in the CMASI waypoint-following construct, but CMASI was designed to be complete enough to model complex mission behavior.\n\
\n\
== Support Data\n\
A number of basic data were defined in order to support the types of information described above.  CMASI declares reusable types that help standardize the interface.  This makes working with CMASI more predictable and allows developers to reduce the amount of code necessary to handle CMASI objects.  Perhaps the most commonly used concept is geographic location.  CMASI declares a 2D and 3D location type that is used by other CMASI structures.  2D geometry types are also widely employed.  As mentioned above, CMASI uses an AbstractGeometry base type for all 2D geometry applications.  There are situations where additional data may need to be passed between applications, but there is no existing field in CMASI to hold that data.  CMASI declares the KeyValuePair type to allow for mapped key-values to be included in certain objects.   There are also data structures that describe the status of a running session, such as the time since the start of the session, and the runtime-multiple value (if the session is part of a simulation that runs faster than real-time.)  These basic data types not only standardize CMASI, but they aid in standardizing extensions to CMASI.  When developers create custom extensions, they can re-use the basic types to save time and create more compatible designs.\n\
\n\
== Using CMASI\n\
\n\
=== Request-Response Model\n\
\n\
The most common way CMASI is used is to employ a request-response model.  CMASI includes a data structure named AutomationRequest.  The request contains a reference to tasks, zones, and aircraft that are to be considered by the automation service.  In order for the AutomationRequest to work correctly, the objects referenced in the request must have been previously declared and transmitted to the automation service.  The automation service responds with an AutomationResponse message that contains a list of MissionCommands and/or VehicleActionCommands. Additionally, the automation service may also send ServiceStatus messages that inform the client of progress towards planning a mission.  This is a classical centralized, full-mission planning approach that has been used for a number of years at AFRL.  Mission planning can take milliseconds to several minutes, or may fail completely if the request contains too many constraints or too few resources.  The Request-Response model allows for controlled mission planning and usually includes a human operator to evaluate and approve/reject the results.\n\
\n\
=== Active Mission Monitoring\n\
When monitoring a mission, the automation service may decide to issue commands based on a change in the mission environment.  Mission monitoring is a higher level of autonomy than the request-response model, but it may be necessary in situations when an operator may not be able to attend to a UAV.  Mission monitoring can also be used in conjunction with a request-response model.  For example, an aircraft has been assigned to patrol a road.  The operator makes a request to the automation service for a patrol path to be set up.  The automation service returns a set of waypoints to patrol that road.  At some later time, the operator designates a KeepOutZone due to changing mission circumstances (e.g. a helicopter flying through the area).  If the automation service is monitoring the situation, it may re-plan automatically to avoid the new KeepOutZone. \n\
',
'= Entities\n\
\n\
== Using Entities in Scenarios\n\
Entities are objects other than air vehicles that are defined by [[CMASI]]. In other words, entities are moving or stationary objects in the scenarios. Entities are defined by the ENTITIES MDM, an LMCP data model. Entities are analogous to air vehicles in [[CMASI]], but add some additional flexibility for scenario developers. Entities can be scripted within a scenario to act as a target. A commanded path, given by a FollowPathCommand, enables entities to move on the ground, or in the air, based on a predetermined path.\n\
\n\
Like air vehicles in [[CMASI]], Entities are defined by an EntityConfiguration, and the state is updated using EntityState messages. Entities can carry payloads, which are described by the PayloadConfiguration base class (from CMASI). EntityStates include PayloadStates (from [[CMASI]]) to update the status of onboard payloads.\n\
\n\
== Creating and using Entities\n\
\n\
Entities are created by introducing an EntityConfiguration in the scenario. To place the entity at a given location, and update the status, an initial EntityState message must also be given in the scenario file. The movement of entities is generally handled by the EntityControl plugin (avtas.amase.entity.EntityControl). EntityControl includes plugins to control various entities in the scenario. The level of control depends on the plugins that are loaded into EntityControl.',
'= Plugin Reference\n\
\n\
Links to descriptions of various AMASE plugins are below.\n\
\n\
{|\n\
| [[Plugin::IconManager| IconManager]]          || Manages the relationship between entities and icons in AMASE\n\
| [[Plugin::EventManager| EventManager]]        || Handles application-wide events\n\
| [[Plugin::WindowService| WindowService]]      || Manages Application windows and the layout of plugins\n\
| [[Plugin::EntityControl| EntityControl]]     || Controls models of entities in AMASE\n\
|}\n\
',
'= Connecting to AMASE\n\
\n\
AMASE includes a Server plugin that enables the connection of clients.  Clients are applications that send and receive data using the [[LMCP]] protocol.  The AMASE server is a TCP server that allows bi-directional transfer of LMCP data. AMASE clients can be very powerful players in an overall simulation.  AMASE clients can issue commands for entities to execute, create new airspaces (such as keep-in or keep-out zones), and respond to task requests.\n\
\n\
== Using LMCP\n\
Since AMASE clients send and receive LMCP objects, it is important to understand what [[LMCP]] is, and be familiar with the library.  When [[LMCP]] code packages are produced using the LMCP PackageMaker, client and server examples are included for each language.  A more sophisticated Java-based example is provided in this tutorial.  The concepts are transferable to the other programming languages.\n\
\n\
Clients require a build of LMCP that includes all of the message data models (MDM) that are desired for the plugin to function.  AMASE applications use the CMASI MDM and the Entities MDM, but other MDMs may be present as well.  It is not necessary that the client have all of the MDMs that the server (AMASE) is using, but only messages loaded into the client\'s LMCP library will be able to be sent or recognized by the client.\n\
\n\
== Connecting to AMASE\n\
In order to connect an AMASE client, AMASE must be running the TcpServer Plugin (\x3Ccode\x3Eavtas.amase.network.TcpServer\x3C/code\x3E). AMASE clients typically connect to port 5555.  However, this port number is configurable.  Check the \x3Ccode\x3EPlugins.xml\x3C/code\x3E file in the AMASE configuration directory to confirm the port number.\n\
\n\
The entry for the TCP server should look like:\n\
\n\
{{{\n\
\x3CPlugin Class="avtas.amase.network.TcpServer"\x3E\n\
    \x3CTCPServer Port="5555"/\x3E\n\
\x3C/Plugin \x3E\n\
}}}\n\
\n\
== An Example Network Client\n\
\n\
An example AMASE client is included in the AMASE source distribution in the \x3Ccode\x3Esrc/examples\x3C/code\x3E folder.  This example uses Java, but other languages will follow a similar style.  In this example we will setup a new project that includes all of the required source and build the application, including [[LMCP]].  This tutorial assumes knowledge of building Java projects and referencing Java jar files.\n\
\n\
=== Building the Network Client\n\
\n\
# Create a new Java Application project in [[http://netbeans.org|Netbeans]] (or an alternative IDE if you prefer)\n\
\n\
# Copy the folder \x3Ccode\x3Eamase.examples.client\x3C/code\x3E from \x3Ccode\x3Esrc/examples\x3C/code\x3E into the \x3Ccode\x3Esrc\x3C/code\x3E folder of the new project directory\n\
\n\
# Run the LMCP Packagemaker (from the \x3Ccode\x3ELMCP\x3C/code\x3E directory) and build an LMCP code package for Java.  Choose the CMASI and Entities MDM files for the build.  Choose your new project directory as the destination.\n\
\n\
# Copy all of the source from the newly formed \x3Ccode\x3Ejava\x3C/code\x3E directory into the \x3Ccode\x3Esrc\x3C/code\x3E directory.\n\
\n\
# Copy \x3Ccode\x3EAmase.jar\x3C/code\x3E (or \x3Ccode\x3EAmase Dev Kit.jar\x3C/code\x3E) from the \x3Ccode\x3Edist\x3C/code\x3E directory of AMASE into your new application directory.\n\
\n\
# Configure the Netbeans project to use the \x3Ccode\x3EAmase.jar\x3C/code\x3E (or \x3Ccode\x3EAmase Dev Kit.jar\x3C/code\x3E) as a referenced library (Properties-\x3ELibraries)\n\
\n\
# Build the project\n\
\n\
# Run amase.examples.client.  It will attempt to connect to AMASE on port 5555.  It will continue to attempt connections until AMASE is run.\n\
\n\
=== Running the Client\n\
\n\
Once the client is built, running it is simple.  First, launch AMASE and load "Example4_AssigningTasks" from the example scenarios directory.  Then launch the client. Hitting the reset button in AMASE will re-load the scenario and send data to the client.  The client will command the aircraft to each loiter and stare at different points.  Using the [[Setup Tool]] you can move the aircraft around and then reload the scenario to see how the client uses a simple distance test to allocate tasks to aircraft.\n\
\n\
The example client is well documented to show how LMCP message traffic is handled and how the client connects to the server.  ',
'= More Examples\n\
\n\
In addition to the [[SimpleExampleApp| Simple Example]] there are other examples provided in the \x3Ccode\x3Esrc/example\x3C/code\x3E folder.  The additional examples provide insight into more advanced AMASE features and show how AMASE can leverage external libraries to add functionality.\n\
\n\
Batch files for the examples are included in the \x3Ccode\x3Erun/examples\x3C/code\x3E directory.\n\
\n\
== Dynamic Zones and Tasks\n\
\n\
This example shows how [[LMCP]] objects can be injected into AMASE scenarios.  This example injects a new zone if the simulation time reaches 5 seconds.  If an aircraft with an ID of 3 is seen, a new CMASI Task is created. This example is illustrative, so nothing is done with the task. However, you can see that the map displays the zone and task when they are created.  Also, by choosing Scenario -\x3E Show Scenario Events from the menu.  Run this example with the scenario file "example scenarios/DynamicZoneAndTask.xml".\n\
\n\
== Closest Approach\n\
\n\
This example introduces a 3rd party library to show a plot of the relative distance between two aircraft.  Run this example with the scenario "ClosestApproachTest".  The plot can be shown by choosing the menu item \x3Ccode\x3EClosest Approach -\x3E Show Plot\x3C/code\x3E at anytime during the scenario.\n\
\n\
This example also includes a MapLayer.  The \x3Ccode\x3Eamase.examples.ExampleMapLayer\x3C/code\x3E class is loaded into the MapPlugin in the config file for the example.\n\
\n\
== AutoZoneAvoidance\n\
\n\
The previous examples demonstrated the use of AMASE plugins, but a key part of AMASE is the [[Plugin::EntityControl]] system.  This example shows a plugin for [[Plugin::EntityControl]] that enables logic to be performed at the entity level.  In this case, an aircraft that has the \x3Ccode\x3Eamase.examples.AutoZoneAvoidance\x3C/code\x3E plugin loaded will automatically steer itself to avoid KeepOutZones.  To demonstrate this, load the scenario file  "example scenarios/AutoZoneAvoidance.xml".  \n\
\n\
Note that the configuration directory, "config/examples/AutoZoneAvoidance" contains the file "EntityControl.xml".  That file specifies that the default aircraft loads the \x3Ccode\x3Eamase.examples.AutoZoneAvoidance\x3C/code\x3E plugin.  For more details, see the discussion of [[Plugin::EntityControl]].\n\
\n\
\n\
\n\
\n\
',
'= Entity Control\n\
\n\
At its core, AMASE is a multi-agent framework. The Entity Control plugin (\x3Ccode\x3Eavtas.amase.entity.EntityControl\x3C/code\x3E) enables agent based behavior in AMASE by managing entities.  The Entity Control system maintains a collection of models (\x3Ccode\x3Eavtas.amase.entity.EntityModel\x3C/code\x3E) to which modules (\x3Ccode\x3Eavtas.amase.entity.EntityModule\x3C/code\x3E) are added.\n\
\n\
Entities are defined by [[LMCP]] objects that are dispatched in the simulation (AirVehicleConfiguration from the [[CMASI]] MDM or EntityConfiguration from the Entities MDM). EntityControl is hierarchical in its structure.  When an EntityConfiguration or AirVehicleConfiguration object is dispatched in the simulation, it creates an EntityModel for that entity.  EntityModels maintain a list of Modules. EntityControl passes appropriate events and timing signals to each entity model.  The model then passes those events and signals to each module. Modules have access to a model-wide data repository to get and set parameters, and can also dispatch events within the model. Additionally, modules can reach back to the application-wide [[Plugin::EventManager|event manager]] to both receive and send application events.\n\
\n\
Like the overall AMASE application, entity modules serve as plugins to their respective model.  Override methods that are needed to implement the desired functionality.\n\
\n\
\x3Cdiv align=\'center\'\x3E\x3Cimg src=\'images/entity_control.png\' /\x3E\x3C/div\x3E\n\
\n\
== Model Configuration\n\
EntityControl is configured using XML data loaded from the configuration file and/or a scenario file. EntityControl expects XML data in order to declare default configurations. EntityControl requires this data to be present in an element named \x3CEntityControl\x3E in the root of the configuration or scenario file. \n\
\n\
Entity model configurations can be listed by ID, type, or class.  When entities are introduced into a scenario (using an instance of EntityConfiguration or a subclass) then EntityControl will create a model and load the appropriate models for that entity.  Because default model configurations can exist in the configuration or the scenario file, configurations in the scenario file will override any conflicting configurations in the  AMASE configuration file.\n\
\n\
Which configuration is loaded is based on the level of precedence for the default configuration.  If a configuration with a matching ID is found, it is used.  Failing that, a configuration with a matching "type" designation (from the EntityConfiguration "type" field) is used.  Then a configuration with a matching class-name is used.  To match, the class name must be given as a fully-qualified java class name for the class corresponding to the EntityConfiguration subclass that was loaded by the scenario. If there is no configuration that matches the above categories, then EntityControl will load an empty model.\n\
\n\
== Default Entities (and Aircraft)\n\
If an AirVehicleConfiguration or EntityConfiguration is published in AMASE, and there is no corresponding "ID", "Type", or "Class" entry, then EntityControl attempts to load a default configuration. For CMASI AirVehicleConfiguration or any subclass thereof, EntityControl will look for a "DefaultAircraft" entry. For an ENTITIES defined EntityConfiguration, or any subclass thereof, EntityControl will use the "DefaultEntity" entry.\n\
\n\
The example below shows a EntityControl configuration: \n\
\n\
{{{\n\
\x3CEntityControl\x3E \n\
    \x3CEntitySetup Class="afrl.entity.GroundVehicle"\x3E \n\
      \x3CModule Class="give.fully.qualified.class.name"/\x3E \n\
      \x3CModule Class="another.fully.qualified.class.name"/\x3E \n\
    \x3C/EntitySetup\x3E \n\
    \x3CEntitySetup Type="jeep"\x3E \n\
      \x3CModule Class="give.fully.qualified.class.name"/\x3E \n\
      \x3CModule Class="another.fully.qualified.class.name"/\x3E \n\
    \x3C/EntitySetup\x3E \n\
    \x3CEntitySetup ID=\u201c2"\x3E \n\
      \x3CModule Class="give.fully.qualified.class.name"/\x3E \n\
      \x3CModule Class="another.fully.qualified.class.name"/\x3E \n\
    \x3C/EntitySetup\x3E \n\
    \x3CDefaultAircraft\x3E\n\
       module entries for default aircraft defined by CMASI AirVehicleConfiguration\n\
    \x3C/DefaultAircraft\x3E\n\
    \x3CDefaultEntity\x3E\n\
       module entries for default entities defined by ENTITIES EntityConfiguration\n\
    \x3C/DefaultEntity\x3E\n\
\x3C/EntityControl\x3E\n\
}}}\n\
\n\
== Entity Exclusion\n\
\n\
EntityControl can be configured to ignore one or more entities in a scenario. This is usually because some other external or internal data source is providing information for the entity.  Specific entities can be excluded from EntityControl using an  exclusion list in the XML document. To add a list of aircraft that are not modeled by EntityControl, add the following section to the \x3CEntityControl\x3E section of the configuration (or scenario) file:\n\
\n\
{{{\n\
\x3CExclusionList\x3E\n\
  \x3CID\x3Eentity id\x3C/ID\x3E \n\
  \x3CID\x3Eanother entity id\x3C/ID\x3E \n\
\x3C/ExclusionList\x3E \n\
}}}\n\
\n\
== Configuring Modules\n\
\n\
EntityModules can also read any data that is included in the XML section for that module.  The example below shows this.  Each module can read this data from, the xml element that is passed in the initialize method.  In this case, the module will receive the Module element that contains the child element "foo".\n\
\n\
{{{\n\
\x3CModule Class="give.fully.qualified.class.name"\x3E\n\
  \x3Cfoo\x3Ebar\x3C/foo\x3E\n\
\x3C/Module\x3E\n\
}}}\n\
',
'= Changes in AMASE 2014 Beta 1\n\
\n\
* Docking framework for GUI elements.\n\
* Combined /Multiflight/ and /EntityControl/ into a single /EntityControl/ plugin\n\
* New configuration system uses configuration folders, allowing custom files for plugins\n\
* Consolidated major interfaces into an abstract /AmasePlugin/ class\n\
* Additional example code includes more advanced AMASE features\n\
* An AMASE icon menu enables application management consistent across AMASE applications\n\
* Added /AeroTools/ to provide higher detail flight modeling\n\
* Better 2D map code improves the API\n\
** Replaced /flatearth/ package with /avtas.map/ to be consistent with naming conventions\n\
** Added features to the /DistanceTool/ layer\n\
** Added an /AuditTrail/ layer for custom display of aircraft history\n\
** Improved operator-like features in ELVIS package, including a new /FlightDirector/ tool\n\
* Uses latest Worldwind version 2.0 for 3D visualization\n\
* Improved inline Javadoc code documentation throughout source tree\n\
* Established a wiki-based documentation system\n\
* Improved the presentation of scenario data \n\
** presented as a tree structure opposed to the old XML display\n\
* Includes the open-source SwingX system for many GUI tools\n\
* Implemented a custom icon system with utilities for adding and displaying decorated icons\n\
* Updated Shapefile system to remove Openmap-derived code.  Now uses Worldwind utilities\n\
* New Controls layer for 2D map allows any Swing component to be added to a map layer\n\
* /Still in development:/ Graphical editing of properties for plugins\n\
\n\
',
'= AMASE C++ Plugins and Entity Modules\n\
\n\
AMASE now has a system for implementing code as an AMASE plugin or as a module for the EntityControl plugin.  "Native" is a Java term used to describe code that is running outside the Java virtual machine interacting directly with code that is running inside the java application.  Typically, native code is implemented in C or C++.  The AMASE native interface uses the standard Java Native Interface (JNI).  It is recommended that the reader be familiar with the JNI.  However, the AMASE native interface abstracts direct JNI calls from the user, so only standard C++ knowledge is required to implement native components.\n\
\n\
This document describes two types of native components that interact with AMASE.  The first is a native /EntityModule/. Entity modules plug into the [[Plugin::EntityControl|EntityControl]] plugin, which is the main plugin that manages all of the entities and aircraft in a scenario.  The second type of native component is a native /AmasePlugin/.  This is a top-level plugin that interacts with AMASE on the main application level.\n\
\n\
== Building the Native Library\n\
\n\
Building the Native module requires the following steps:\n\
\n\
# Add all of the source and headers for the native module infrastructure, located in the "native" directory to your project.\n\
# Include the appropriate JNI headers as \u201cinclude\u201d directories. The JNI headers are included in the standard Java development kit (JDK) in the include folder. There is a standard JNI header and a sub-folder containing platform specific headers. Include both the top-level folder and the operating system folder.\n\
# Build the LMCP library for your AMASE project.  You will need to build a C++ package with all of the appropriate MDMs for your AMASE application.    LMCP automatically generates a Visual Studio project file and GCC makefile to build the library.  Once the LMCP library is built, point to the static library from your native module project.  Also add the "cpp" directory of the LMCP build to your "include" list so you can compile code that references LMCP namespaces.\n\
# Build your native module project as a dynamic library (.so on Linux, .dll on Windows, .dylib on MacOS)\n\
\n\
\n\
== Native Entity Modules\n\
\n\
The AMASE Native Module requires both Java and C++ (native) code to work.  The Java component is the avtas.amase.natives.NativeModule plugin.  This module must be added to [[Plugin::EntityControl|EntityControl]] to enable communications with the native module.   On the native side, the code must be compiled into a library that is compatible with Java platform that is to run the native module.  This document describes the process for creating a native module and adding it to an AMASE application.\n\
\n\
To use the native module system, it is recommended that the user be familiar with how [[Plugin::EntityControl|EntityControl]] modules work.  Additionally, the user should be proficient in C++ programming, and have familiarity with the LMCP object protocol. \n\
\n\
=== Writing the Native Module\n\
\n\
Native modules are defined per entity or aircraft, like any other EntityControl module on the Java side of AMASE.  All source for the C++ code is in the "natives" directory. A Native entity module extends the base class EntityModule, which is defined in EntityModule.h.   modules can override the following functions to provide the same level of functionality as a Java module:\n\
\n\
\x3Ccode\x3E void step(double sim_time, double timestep) \x3C/code\x3E\n\
\n\
The step function is called every time the model receives an update from the simulation timer.  All times are in seconds of simulation time.\n\
\n\
\x3Ccode\x3E void initialize(unsigned int entity_id, avtas::lmcp::Node* xmlNode) \x3C/code\x3E\n\
\n\
This method is called only once in a scenario, when the module is created for a given entity/aircraft.  The entity ID is a unique id for the entity/aircraft in the scenario. The xmlNode parameter contains XML-formatted data that is contained in the configuration or scenario file for this module.  Note that the XML content is not the entire file, but is only the content that is the child of the module declaration element in the file.  See the code under avtas/lmcp for the handling of XML data using the LMCP library. \n\
\n\
\x3Ccode\x3E void  model_event_occured(avtas::lmcp::Object* obj)\x3C/code\x3E\n\
\n\
This method is called every time an event occurs within the model for the entity/aircraft.  Model events can be the result of an application-wide event (such as a new MissionCommand) or they can be issued by another module within the model.  (e.g., The avtas.amase.multiflight.WaypointFollower code issues VehicleAction objects that are encountered as the aircraft reaches each waypoint).  It is important to remember to call delete on every object that is not maintained for later use, otherwise the application is likely to run out of memory.\n\
\n\
\x3Ccode\x3E void app_event_occured (avtas::lmcp::Object* obj) \x3C/code\x3E\n\
\n\
This is similar to \x3Ccode\x3Emodel_event_occured\x3C/code\x3E, except that it is for every event in the application. As noted above, remember to call delete on objects that are not kept for use. \n\
\n\
\x3Ccode\x3E void shutdown() \x3C/code\x3E\n\
\n\
This is called when the model is destroyed within AMASE.  This occurs when a new scenario is loaded or the current scenario is reloaded.  This method should be implemented to perform clean up of memory.\n\
\n\
An example implementation is provided in the ExampleModule.cpp and ExampleModule.h files.\n\
\n\
=== Configuring AMASE to run a Native Module\n\
An EntityControl or MultiFlight model is made up of a series of modules in AMASE.  (The AMASE users guide has more information regarding the structure of those systems.  It is recommended that the user is familiar with the creation and management of entity/aircraft models in AMASE before attempting a native module implementation.)   A native module is added to an entry in the AMASE configuration or scenario file just like any other EntityControl or Multiflight module.  The excerpt below shows an example of the declaration of a native module in AMASE.\n\
\n\
\n\
{{{\n\
\x3CModule Class="avtas.amase.natives.NativeModule"\x3E\n\
  \x3CLibrary\x3EExampleModuleLibrary\x3C/Library\x3E\n\
  \x3CModuleType\x3EExample\x3C/ModuleType\x3E\n\
  \x3C!-- additional XML data --\x3E\n\
\x3C/Module\x3E\n\
}}}\n\
\n\
In this example, a module library is loaded that is expected to contain an implementation of a module called \u201cExample\u201d.  The library (ExampleModuleLibary) must be on the library path for AMASE.  The library path is set up using the \u2013Djava.library.path=\x3Cpath\x3E parameter when running AMASE.   On the Java side, the module avtas.amase.natives.NativeModule is the bridge between AMASE and the native code.  NativeModule implements FlightModule and EntityModule, so it is compatible with both Multiflight and EntityControl. When the module is loaded, it is initialized with all of the XML data that is contained below the level of \u201cModule\u201d, which means that configuration data can be used by the native module.  Note that on Linux and MacOS platforms, the library might have the prefix "lib" (e.g. libExampleModuleLibrary.so).  Do not include the \u201clib\u201d prefix in the Library entry in the module configuration.\n\
To load the NativeModule into your AMASE application, include the source from \u201cjava src\u201d in your project.  This folder contains the NativeModule module code.  Rebuild AMASE with the new NativeModule java support.\n\
\n\
===Interacting with the Simulation\n\
\n\
When AMASE is running, the module functions listed above will be called by AMASE.  However, there may also be a need to publish events to AMASE from the native module.  This may be in response to a received event, or may occur for any other reason.  To send LMCP events to AMASE, there are two callback functions available on the native side:\n\
\n\
\x3Ccode\x3Evoid EntityModule::fireModelEvent(avtas::lmcp::Object* object)\x3C/code\x3E\n\
\n\
This function fires LMCP objects to all other modules currently loaded for the entity or aircraft in which the native module resides.  Note that this method DOES NOT publish events beyond the EntityControl/Multiflight model.\n\
\n\
\x3Ccode\x3Evoid EntityModule::fireApplicationEvent(avtas::lmcp::Object* object)\x3C/code\x3E\n\
\n\
This function dispatches an event to the entire application.  Note that events issued to the entire application from a native module will not be received by the module issuing the event via the app_event_occurred function.\n\
\n\
== Native Plugins\n\
\n\
AMASE native plugins are very similar in structure to AMASE native entity modules.  The native plugin C++ code is in the native folder under \x3Ccode\x3Enative_plugin\x3C/code\x3E. Native plugins inherit from \x3Ccode\x3EAmasePlugin\x3C/code\x3E.  The functions to be implemented in the native plugin are as follows:\n\
\n\
\x3Ccode\x3E void step(double sim_time, double timestep) \x3C/code\x3E\n\
\n\
The step function is called every time the application receives an update from the simulation timer.  All times are in seconds of simulation time.\n\
\n\
\x3Ccode\x3E void initialize(avtas::lmcp::Node* xmlNode, char* config_dir) \x3C/code\x3E\n\
\n\
This method is called only once in a scenario, when the plugin is created at startup.  The xmlNode parameter contains XML-formatted data that is contained in the configuration or scenario file for this plugin.  Note that the XML content is not the entire file, but is only the content that is the child of the plugin declaration element in the file.  See the code under avtas/lmcp for the handling of XML data using the LMCP library.   The configDir points to the location in the file system that contains the configuration data for the AMASE application.  This includes the Plugins file as well as any accessory files used by the AMASE plugins. \n\
\n\
\x3Ccode\x3E void app_event_occured (avtas::lmcp::Object* obj) \x3C/code\x3E\n\
\n\
This method is called every time an LMCP event occurs within the application.  It is important to remember to call delete on every object that is not maintained for later use, otherwise the application is likely to run out of memory.\n\
\n\
\x3Ccode\x3E void shutdown() \x3C/code\x3E\n\
\n\
This is called when the plugin is removed from AMASE or the user shuts down the application.  \n\
\n\
\n\
=== Configuring AMASE to run a Native Plugin\n\
\n\
AMASE plugins are declared in the \x3Ccode\x3EPlugins.xml\x3C/code\x3E file of the configuration directory.  AMASE native plugins are declared through a proxy plugin (\x3Ccode\x3Eavtas.amase.natives.NativePlugin\x3C/code\x3E) that in turn creates the native plugin. The excerpt below shows an example of the declaration of a native plugin in AMASE.\n\
\n\
{{{\n\
\x3CPlugin Class="avtas.amase.natives.NativePlugin"\x3E\n\
  \x3CLibrary\x3EExamplePluginLibrary\x3C/Library\x3E\n\
  \x3CPluginType\x3EExamplePlugin\x3C/PluginType\x3E\n\
  \x3C!-- additional XML data --\x3E\n\
\x3C/Plugin\x3E\n\
}}}\n\
\n\
\n\
=== Interacting with the Simulation\n\
\n\
When AMASE is running, the module functions listed above will be called by AMASE.  However, there may also be a need to publish events to AMASE from the native module.  This may be in response to a received event, or may occur for any other reason.  To send LMCP events to AMASE, there are two callback functions available on the native side:\n\
\n\
\x3Ccode\x3Evoid AmasePlugin::fireApplicationEvent(avtas::lmcp::Object* object)\x3C/code\x3E\n\
\n\
This function dispatches an event to the entire application.  Note that events issued to the entire application from a native module will not be received by the module issuing the event via the app_event_occurred function.\n\
\n\
\n\
\n\
'
];

/* DFQRCTsKlU-0000034-END */

/* ]]> */
</script>
<title woas_permanent="1">Main Page</title>
<style type="text/css" woas_permanent="1" woas_core_style="1">/* CSS used when loading/saving WoaS; readonly */
body {
	margin: 0px;
	padding: 0px;
	border-width: 0px;
	font-family: Georgia, verdana;
	background-color: #F0F0F5; /* to match layout; no name */
}
#loading_overlay {
	position: absolute;
	z-index: 100;
	left: 0px;
	top: 0px;
	bottom: 0px;
	color: 	#000080; /* navy */
	font-size: large;
	text-align: center
}
#woas_debug_console {
	width: 50%;
	margin: 3em auto
}
#woas_debug_log {
	width: 100%
}
#woas_wait_text, #woas_pwd_mask, #woas_header_wrap, #woas_menu_wrap, #woas_page_wrap,
#woas_edit_wrap, #woas_custom_accesskeys, #woas_footer_panel, #woas_debug_log_clear {
	display: none
}
</style>
<script woas_permanent="1" language="javascript" type="text/javascript">
/* <![CDATA[ */
/*** src/aes.js ***/
// AES encryption
// license: GNU/GPLv2
// original code from http://home.versatel.nl/MAvanEverdingen/Code/
// this is a javascript conversion of a C implementation by Mike Scott
// adapted for WoaS by legolas558
// namespace wrapping by pvhl

// namespace wrapper for woas.AES
(function() {
	
var bData = null,
	sData = null,
	aes_i = null,
	aes_j = null,
	tot = null,
	key =  [],
	wMax =  0xFFFFFFFF,
	aesNk = null,
	aesNr = null,
	aesPows = null,
	aesLogs = null,
	aesSBox = null,
	aesSBoxInv = null,
	aesRco = null,
	aesFtable = null,
	aesRtable = null,
	aesFi = null,
	aesRi = null,
	aesFkey = null,
	aesRkey = null;

function rotb(b,n){ return ( b<< n | b>>>( 8-n) ) & 0xFF; }
function rotw(w,n){ return ( w<< n | w>>>(32-n) ) & wMax; }
function getW(a,i){ return a[i]|a[i+1]<<8|a[i+2]<<16|a[i+3]<<24; }
function setW(a,i,w){ a.splice(i,4,w&0xFF,(w>>>8)&0xFF,(w>>>16)&0xFF,(w>>>24)&0xFF); }
function setWInv(a,i,w){ a.splice(i,4,(w>>>24)&0xFF,(w>>>16)&0xFF,(w>>>8)&0xFF,w&0xFF); }
function getB(x,n){ return (x>>>(n*8))&0xFF; }

function aesMult(x, y){ return (x&&y) ? aesPows[(aesLogs[x]+aesLogs[y])%255]:0; }

function aesPackBlock() {
	return [ getW(bData,aes_i), getW(bData,aes_i+4),
			getW(bData,aes_i+8), getW(bData,aes_i+12) ];
}

function aesUnpackBlock(packed){
  for ( var mj=0; mj<4; mj++,aes_i+=4) setW( bData, aes_i, packed[mj] );
}

function aesXTime(p){
  p <<= 1;
  return p&0x100 ? p^0x11B : p;
}

function aesSubByte(w){
  return aesSBox[getB(w,0)] | aesSBox[getB(w,1)]<<8 | aesSBox[getB(w,2)]<<16 | aesSBox[getB(w,3)]<<24;
}

function aesProduct(w1,w2){
  return aesMult(getB(w1,0),getB(w2,0)) ^ aesMult(getB(w1,1),getB(w2,1))
       ^ aesMult(getB(w1,2),getB(w2,2)) ^ aesMult(getB(w1,3),getB(w2,3));
}

function aesInvMixCol(x){
  return aesProduct(0x090d0b0e,x)     | aesProduct(0x0d0b0e09,x)<<8 |
         aesProduct(0x0b0e090d,x)<<16 | aesProduct(0x0e090d0b,x)<<24;
}

function aesByteSub(x){
  var y=aesPows[255-aesLogs[x]];
  x=y;  x=rotb(x,1);
  y^=x; x=rotb(x,1);
  y^=x; x=rotb(x,1);
  y^=x; x=rotb(x,1);
  return x^y^0x63;
}

// Generate static tables
(function(){
  var i,j,m,y;
  aesPows = [ 1,3 ];
  aesLogs = [ 0,0,null,1 ];
  aesSBox = new Array(256);
  aesSBoxInv = new Array(256);
  aesFtable = new Array(256);
  aesRtable = new Array(256);
  aesRco = new Array(30);

  for ( i=2; i < 256; i++){
    aesPows[i]=aesPows[i-1]^aesXTime( aesPows[i-1] );
    aesLogs[aesPows[i]]=i;
  }

  aesSBox[0]=0x63;
  aesSBoxInv[0x63]=0;
  for ( i=1; i < 256; i++){
    y=aesByteSub(i);
    aesSBox[i]=y; aesSBoxInv[y]=i;
  }

  for (i=0,y=1; i < 30; i++){ aesRco[i]=y; y=aesXTime(y); }

  for ( i=0; i < 256; i++){
    y = aesSBox[i];
    aesFtable[i] = aesXTime(y) | y<<8 | y<<16 | (y^aesXTime(y))<<24;
    y = aesSBoxInv[i];
    aesRtable[i]= aesMult(14,y) | aesMult(9,y)<<8 |
                  aesMult(13,y)<<16 | aesMult(11,y)<<24;
  }

  aesFi = new Array(12);
  aesRi = new Array(12);

  for (m=j=0;j<4;j++,m+=3){
    aesFi[m]=(j+1)%4;
    aesFi[m+1]=(j+2)%4;
    aesFi[m+2]=(j+3)%4;
    aesRi[m]=(4+j-1)%4;
    aesRi[m+1]=(4+j-2)%4;
    aesRi[m+2]=(4+j-3)%4;
  }

}());

function aesInit(){
  key=key.slice(0,43);
  var i,k;
  var j = 0;
  var l = key.length;

  while ( l!=16 && l!=24 && l!=32 && l!=43) key[l++]=key[j++];

  aesNk = key.length >>> 2;
  aesNr = 6 + aesNk;

  var N=4*(aesNr+1);
  aesFkey = new Array(N);
  aesRkey = new Array(N);

  for (i=j=0;i< aesNk;i++,j+=4) aesFkey[i]=getW(key,j);

  for (k=0,j=aesNk;j < N;j+=aesNk,k++){
    aesFkey[j]=aesFkey[j-aesNk]^aesSubByte(rotw(aesFkey[j-1], 24))^aesRco[k];
    if (aesNk<=6)
      for (i=1;i < aesNk && (i+j) < N;i++) aesFkey[i+j]=aesFkey[i+j-aesNk]^aesFkey[i+j-1];
    else{
      for (i=1;i<4 &&(i+j) < N;i++) aesFkey[i+j]=aesFkey[i+j-aesNk]^aesFkey[i+j-1];
      if ((j+4) < N) aesFkey[j+4]=aesFkey[j+4-aesNk]^aesSubByte(aesFkey[j+3]);
      for (i=5;i < aesNk && (i+j) < N;i++) aesFkey[i+j]=aesFkey[i+j-aesNk]^aesFkey[i+j-1];
    }
  }

  for (j=0;j<4;j++) aesRkey[j+N-4]=aesFkey[j];
  for (i=4;i < N-4;i+=4){
    k=N-4-i;
    for (j=0;j < 4;j++) aesRkey[k+j]=aesInvMixCol(aesFkey[i+j]);
  }
  for (j=N-4;j < N;j++) aesRkey[j-N+4]=aesFkey[j];
}

function aesClose(){
  aesFkey=aesRkey=null;
}

function aesRounds( block, key, table, inc, box ){
  var tmp = new Array( 4 );
  var i,j,m,r;

  for ( r=0; r<4; r++ ) block[r]^=key[r];
  for ( i=1; i < aesNr; i++ ){
    for (j=m=0;j<4;j++,m+=3){
      tmp[j]=key[r++]^table[block[j]&0xFF]^
			rotw(table[(block[inc[m  ]] >>> 8)&0xFF], 8)^
			rotw(table[(block[inc[m+1]] >>>16)&0xFF],16)^
			rotw(table[(block[inc[m+2]] >>>24)&0xFF],24);
    }
    var t=block; block=tmp; tmp=t;
  }

  for (j=m=0;j<4;j++,m+=3)
    tmp[j]=key[r++]^box[block[j]&0xFF]^
           rotw(box[(block[inc[m  ]] >>> 8)&0xFF], 8)^
           rotw(box[(block[inc[m+1]] >>>16)&0xFF],16)^
           rotw(box[(block[inc[m+2]] >>>24)&0xFF],24);
  return tmp;
}

function _encrypt(){
  aesUnpackBlock( aesRounds(aesPackBlock(), aesFkey, aesFtable, aesFi, aesSBox ) );
}

function _decrypt(){
  aesUnpackBlock( aesRounds(aesPackBlock(), aesRkey, aesRtable, aesRi, aesSBoxInv ) );
}

// Blockcipher

function blcEncrypt(enc){
	if (tot === 0){
		if (key.length < 1) return;
		for (aes_i=0; aes_i<16; ++aes_i) bData.unshift( _rand(256) );
		while( bData.length%16 !== 0 ) bData.push(0);
		tot = bData.length;
		aesInit();
	}else{
		for (aes_j=aes_i; aes_j < aes_i+16; aes_j++)
		bData[aes_j] ^= bData[aes_j-16];
		enc();
	}
	if (aes_i >= tot) aesClose();
}

function blcDecrypt(dec){
	// initialize length
	if (tot === 0){
		if (key.length<1) return false;
		aes_i=16;
		tot = bData.length;
		if ( (tot%16) || (tot < aes_i) ) {
			woas.log('AES: Incorrect length (tot='+tot+', aes_i='+aes_i+')'); //log:1
			return false;
		}
		aesInit();
	} else {
		aes_i=tot-aes_i;
		dec();
		for (aes_j=aes_i-16; aes_j < aes_i; aes_j++) bData[aes_j] ^= bData[aes_j-16];
		aes_i = tot+32-aes_i;
	}
	if (aes_i>=tot){
		aesClose();
		bData.splice(0,16);
		// remove 0s added for padding (supposedly!)
		while(bData[bData.length-1] === 0) bData.pop();
	}
	return true;
}

// @module aes
woas.AES = {
	// sets global key to the utf-8 encoded key (byte array)
	setKey: function(sKey) {
		key = woas.utf8.encode_to_array(sKey);
	},
	clearKey: function(){
		key = [];
	},
	// keep 'key' private to this code
	isKeySet: function(){
		return key.length > 0;
	},
	// returns an array of encrypted characters
	encrypt: function(raw_data){
		bData = woas.utf8.encode_to_array(raw_data);
		
		aes_i=tot=0;
		do{ blcEncrypt(_encrypt); } while (aes_i<tot);
		
		var rv = bData;
		bData = null;
		return rv;
	},

	// decrypts an array of encrypted characters
	decrypt: function(raw_data){
		bData = raw_data;
		
		aes_i=tot=0;
		do {
			if (!blcDecrypt(_decrypt))
				return null;
		} while (aes_i<tot);
		
		sData = woas.utf8.decode_from_array(bData);
		bData = [];
		var rv = sData;
		sData = null;
		return rv;
	}
};

}()); // end of AES closure

/*** src/framework.js ***/

woas.browser = {
	// browsers - when different from 'false' it contains the version string
	ie: false,
	firefox: false,
	opera: false,
	safari: false,
	chrome: false,

	// versions - used internally, should not be used by external plugins
	ie6: false, ie8: false,
	firefox2: false,
	firefox3: false, firefox_new: false,

	// engines - set to true when present
	// gecko and webkit will contain the engine version
	gecko: false, webkit: false, presto: false, trident: false
};

// used to match browser version
var m;

if((navigator.userAgent).indexOf("Opera")!=-1) {
	m = navigator.userAgent.match(/Opera\/(\S*)/);
//	if (m && m[1])
		woas.browser.opera = m[1];
} else if (navigator.userAgent.indexOf("Chrome") != -1) {
	// detect version
	m = navigator.userAgent.match(/Chrome\/([^\s]+)/);
//	if (m && m[1])
		woas.browser.chrome = m[1];
} else if (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1) {
	// Safari never publicizes its version
	woas.browser.safari = true;
} else if(navigator.appName == "Netscape") {
	// check that it is Gecko first
	woas.browser.firefox = woas.browser.gecko = (new RegExp("Gecko\\/\\d")).test(navigator.userAgent);
	// match also development versions of Firefox "Shiretoko" / "Namoroka"
	if (woas.browser.gecko) {
		// match the last word of userAgent
		m = navigator.userAgent.match(/rv:([^\s\)]*)/);
		woas.browser.gecko = m[1];
		switch (woas.browser.gecko.substr(0,3)) {
			case "1.8":
				woas.browser.firefox2 = true;
			break;
			case "1.9":
				woas.browser.firefox3 = true;
			break;
			default:
				if (Number(woas.browser.gecko.substr(0,3)) > 1.9) {
					woas.browser.firefox_new = true;
				}
		}
	} // not Gecko
} else if((navigator.appName).indexOf("Microsoft")!=-1) {
	woas.browser.ie8 = document.documentMode ? true : false;
	if (!woas.browser.ie8)
		woas.browser.ie6 = window.XMLHttpRequest ? false : true;
	// detect version
	m = navigator.userAgent.match(/MSIE\s([^;]*)/);
//	if (m && m[1])
		woas.browser.ie = m[1];
}

// finds out if Opera is trying to look like Mozilla
if (woas.browser.firefox && (navigator.product != "Gecko")) {
	woas.browser.firefox = woas.browser.firefox2
	= woas.browser.firefox3 = woas.browser.firefox_new = false;
	if (typeof window.opera != "undefined")
		woas.browser.opera = true;
}

// finds out if Opera is trying to look like IE
if (woas.browser.ie && (typeof window.opera != "undefined")) {
	woas.browser.ie = woas.browser.ie6 = woas.browser.ie8 = false;
	woas.browser.opera = true;
}

// detect engine type
if (woas.browser.ie)
	woas.browser.trident = true;
else if (woas.browser.chrome || woas.browser.safari) {
	m = navigator.userAgent.match(/AppleWebKit\/(\S*)/);
//    if (m && m[1])
		woas.browser.webkit = m[1];
} else if (woas.browser.opera)
	woas.browser.presto = true;

var is_windows = (navigator.appVersion.toLowerCase().indexOf("windows")!=-1);

woas._server_mode = (document.location.toString().match(/^file:\/\//) ? false:true);

// set to true if we need Java-based file load/save
// PVHL: changed to anything we don't know how to handle
woas.use_java_io = !woas.browser.ie && !woas.browser.firefox;

// returns the DOM element object given its id - enables a try/catch mode when debugging
if (woas.config.debug_mode) {
	// returns the DOM element object given its id, alerting if the element is not found (but that would never happen, right?)
	function d$(id){ try{return document.getElementById(id);}catch(e){woas.crash("d$('"+id+"') invalid reference:\n\n"+e);} }
} else {
	// much faster version
	function d$(id){return document.getElementById(id);}
}

d$.checked = function(id) {
	//FIXME: configuration should not be changed by reading a property!!
	woas.cfg_changed = true;
	if (d$(id).checked)
		return true;
	return false;
};

d$.hide = function(id) {
	d$(id).style.display = 'none';
};

d$.show = function(id, inline) {
	d$(id).style.display = inline ? 'inline' : 'block';
};

d$.is_visible = function(id) {
	return !!d$(id).offsetWidth;
};

// always resizes to be safe
d$.toggle = function(id, inline) {
	var d = d$(id);
	d.style.display = d.offsetWidth ? 'none' : inline ? 'inline' : 'block';
	woas.ui._resize();
};

// set/reset a class, and resize if optional r is true; may make resize required
// experimentally used by debug console
d$.toggle_cls = function(c, r) {
	var o = {};
	o[c] = !woas.ui.display(c);
	woas.ui.display(o);
	if (r) {
		woas.ui._resize();
	}
};

// PVHL: shallow object copy; prefer shallow extend, with filter; was d$.clone
woas.clone = function(obj) {
	var nobj = {};
	for (var i in obj) {
		nobj[i] = obj[i];
	}
	return nobj;
};

// fixes the Array prototype for older browsers
if (typeof Array.prototype.push == "undefined") {
  Array.prototype.push = function(str) {
    this[this.length] = str;
  };
}

// the following methods complete the Array object for non-compliant browsers
if (typeof Array.prototype.splice == "undefined") {
  Array.prototype.splice = function(offset, length) {
    var temp = [];
    for (var i = this.length - 1; i >= 0; i--) {
      if (i < offset || i > (offset + length - 1)) {
        temp[temp.length] = this[i];
      }
      this.length--;
    }
    for (i = temp.length - 1; i >= 0; i--) {
      this[this.length] = temp[i];
    }
    return this;
  };
}

if (typeof Array.prototype.indexOf == "undefined") {
	Array.prototype.indexOf = function(val, fromIndex) {
		if (typeof(fromIndex) != 'number') fromIndex = 0;
		for (var index = fromIndex,len = this.length; index < len; index++)
			if (this[index] == val) return index;
		return -1;
	};
}

// implements a custom function which returns an array with unique elements - deprecated
Array.prototype.toUnique = function() {
	var a_o = {}, new_arr = [];
	var l=this.length;
	for(var i=0; i<l;i++) {
		if (a_o[this[i]]===undefined) {
			a_o[this[i]] = true;
			new_arr.push(this[i]);
		}
	}
	if (new_arr.length!=l)
		return new_arr;
	return this;
};

// provide regex escaping
// thanks to S.Willison
RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = ['/', '.', '*', '+', '?', '|', '$', '(', ')', '[', ']', '{', '}', "\\" ];
    arguments.callee.sRE = new RegExp(
      "(\\" + specials.join("|\\") + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, "\\$1");
};

// repeat string s for n times
 if (typeof String.prototype.repeat == "undefined") {
	String.prototype.repeat = function(n) {
		var r = "";
		while (--n >= 0) r += this;
		return r;
	};
}

// return a random integer given the maximum value (scale)
function _rand(scale) {
	return Math.floor(Math.random() * scale);
}

// returns a random string of given string_length
function _random_string(string_length) {
	var chars = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
	var randomstring = '';
	for (var i=0; i < string_length; i++) {
		var rnum = _rand(chars.length);
		randomstring += chars.charAt(rnum);
	}
	return randomstring;
}

// converts the number of bytes to a human readable form
function _convert_bytes(bytes, p) {
	var U=['bytes','Kb','Mb','Gb','Pb'], n = 0;
	if (typeof p !== 'number') { p = 2; }
	bytes = Math.ceil(bytes);
	while (bytes >= 1024 && n < 4) {
		 ++n;
		 bytes /= 1024;
	}
	return bytes.toFixed(p).replace(/\.0+$/, "") +' '+ U[n];
}
/*
// implement an sprintf() bare function
String.prototype.sprintf = function() {
	// check that arguments are OK
	if (typeof arguments == "undefined") { return null; }
	// next argument to pick
	var i_pos = 0, max_pos = arguments.length - 1;
	var fmt_args = arguments;
	return this.replace(/%[sd]/g, function(str) {
		// replace with the original unparsed token in case of undefined parameter
		if (i_pos > max_pos)
			return str;
		//if (str == '%d')
			//return Number(arguments[i_pos++]);
		//return '%s' string
		return fmt_args[i_pos++];
	});
};
*/
/* PVHL:
- previous version was't catching undefined arguments in Firefox
- string can now include a '%': use '100%% correct, %s'. Should drop %d; this isn't sprintf.
- added a log msg if called with no arguments.
- consider change of name; sprintf means nothing to js programmers plus this isn't that. fmt?
- we need to have better i18n support; better to ask for a formatted string by passing
  arguments to an i18n object than add to String prototype; gives better error messages too.
- could have log error message if arguments not as expected. If keeping %d/%s then should
  check if correct.
*/
String.prototype.sprintf = function() {
	// check arguments exist; return original string if not
	if (!arguments || arguments.length === 0) {
		woas.log("ERROR: String.sprintf called with no arguments on '" + this + "'");
		return this;
	}
	var i = 0, a = arguments;
	return this.replace(/%((%)|[sd])/g, function(str, $1, keep) {
		// keep original unparsed token in case of undefined parameter; use %% for a %
		return keep || (i < a.length ? a[i++] : str);
	});
};

// get filename of currently open file in browser
function _get_this_filename() {
	var filename = unescape(document.location.toString().split("?")[0]);
	if (woas.browser.opera)
		filename = filename.replace(/^file:\/\/[^\/]+/, '');
	else {
		if (filename.indexOf("file://") === 0) // all browsers
			filename = filename.substr(7);
		if (filename.indexOf("///")===0) // firefox
			filename = filename.substr(1);
	}
	//TODO: check that 'g' can be removed
	filename = filename.replace(/#.*$/g, ""); // remove fragment (if any)
	if (is_windows) {
		// convert unix path to windows path
		filename = filename.replace(reFwdSlash, "\\");
		if (filename.substr(0,2)!="\\\\") { // if this is not a network path - will be true in case of Firefox for example
			// remove leading slash before unit:
			if (filename.match(/^\\\w:\\/))
				filename = filename.substr(1);
			if (filename.charAt(1)!=':') {
				if (woas.browser.ie)
					filename = "\\\\"+filename;
			}
		}
	}
	return filename;
}

function ff_fix_focus() {
	//runtime fix for Firefox bug 374786
	if (woas.browser.firefox)
		d$("woas_page").blur();
}

if (is_windows) {
	var reFwdSlash = new RegExp("/", "g");
	woas.fix_path_separators = function(path) {
		return path.replace(reFwdSlash, woas.DIRECTORY_SEPARATOR);
	};
} else { // UNIX or similar, no path change
	woas.fix_path_separators = function(path) {
		return path;
	};
}

woas.base64 = {
	_b64arr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
	reValid: /^[A-Za-z0-9+\/=]+$/
};

if (window.atob) {
	woas.base64.encode = function(input) {
		return btoa(input);
	};

	woas.base64.encode_array = function(input) {
		var i, l = input.length, arr = [];
		for (i = 0; i < l; i++) {
			arr[i] = String.fromCharCode(input[i]);
		}
		return btoa(arr.join(''));
	};

	woas.base64.decode = function(input, z) {
		if (!z || z > input.length) {
			z = input.length;
		}
		return atob(input.substr(0, z));
	};

	woas.base64.decode_array = function(input, z) {
		var i, l, arr = [];
		if (!z || z > input.length) {
			z = input.length;
		}
		input = atob(input.substr(0, z));
		l = input.length;
		for (i = 0; i < l; i++) {
			arr[i] = input.charCodeAt(i);
		}
		return arr;
	};
} else { //IE
	woas.base64.encode = function(input) {
		var c1, c2, c3, i = 0, left, z, output = [];
		left = input.length % 3;
		z = input.length - left;
		while (i < z) {
			c1 = input.charCodeAt(i++);
			c2 = input.charCodeAt(i++);
			c3 = input.charCodeAt(i++);
			output.push(this._b64arr.charAt(c1 >> 2));
			output.push(this._b64arr.charAt(((c1 & 3) << 4) | (c2 >> 4)));
			output.push(this._b64arr.charAt(((c2 & 15) << 2) | (c3 >> 6)));
			output.push(this._b64arr.charAt(c3 & 63));
		}
		if (left) {
			c1 = input.charCodeAt(i++);
			c2 = left === 2 ? input.charCodeAt(i++) : Number.NaN;
			output.push(this._b64arr.charAt(c1 >> 2));
			output.push(this._b64arr.charAt(((c1 & 3) << 4) | (c2 >> 4)));
			output.push(isNaN(c2) ? "=" : this._b64arr.charAt(((c2 & 15) << 2)));
			output.push('=');
		}
		return output.join('');
	};

	woas.base64.encode_array = function(input) {
		var c1, c2, c3, i = 0, left, z, output = [];
		left = input.length % 3;
		z = input.length - left;
		while (i < z) {
			c1 = input[i++];
			c2 = input[i++];
			c3 = input[i++];
			output.push(this._b64arr.charAt(c1 >> 2));
			output.push(this._b64arr.charAt(((c1 & 3) << 4) | (c2 >> 4)));
			output.push(this._b64arr.charAt(((c2 & 15) << 2) | (c3 >> 6)));
			output.push(this._b64arr.charAt(c3 & 63));
		}
		if (left) {
			c1 = input[i++];
			c2 = left === 2 ? input[i++] : Number.NaN;
			output.push(this._b64arr.charAt(c1 >> 2));
			output.push(this._b64arr.charAt(((c1 & 3) << 4) | (c2 >> 4)));
			output.push(isNaN(c2) ? "=" : this._b64arr.charAt(((c2 & 15) << 2)));
			output.push('=');
		}
		return output.join('');
	};

	woas.base64.decode = function(input, z) {
		var c1, c2, c3, enc1, enc2, enc3, enc4, i = 0, l = input.length, output = [];
		z = !z || z > l ? l - 4 : z - 4;
		if (z >= 0) {
			while (i < z) {
				enc1 = this._b64arr.indexOf(input.charAt(i++));
				enc2 = this._b64arr.indexOf(input.charAt(i++));
				enc3 = this._b64arr.indexOf(input.charAt(i++));
				enc4 = this._b64arr.indexOf(input.charAt(i++));
				output.push(String.fromCharCode((enc1 << 2) | (enc2 >> 4)));
				output.push(String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2)));
				output.push(String.fromCharCode(((enc3 & 3) << 6) | enc4));
			}
			enc1 = this._b64arr.indexOf(input.charAt(i++));
			enc2 = this._b64arr.indexOf(input.charAt(i++));
			enc3 = this._b64arr.indexOf(input.charAt(i++));
			enc4 = this._b64arr.indexOf(input.charAt(i++));
			output.push(String.fromCharCode((enc1 << 2) | (enc2 >> 4)));
			if (enc3 !== 64) {
				output.push(String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2)));
			}
			if (enc4 !== 64) {
				output.push(String.fromCharCode(((enc3 & 3) << 6) | enc4));
			}
		}
		return output.join('');
	};

	woas.base64.decode_array = function(input, z) {
		var c1, c2, c3, enc1, enc2, enc3, enc4, i = 0, l = input.length, output = [];
		z = !z || z > l ? l - 4 : z - 4;
		if (z >= 0) {
			while (i < z) {
				enc1 = this._b64arr.indexOf(input.charAt(i++));
				enc2 = this._b64arr.indexOf(input.charAt(i++));
				enc3 = this._b64arr.indexOf(input.charAt(i++));
				enc4 = this._b64arr.indexOf(input.charAt(i++));
				output.push((enc1 << 2) | (enc2 >> 4));
				output.push(((enc2 & 15) << 4) | (enc3 >> 2));
				output.push(((enc3 & 3) << 6) | enc4);
			}
			enc1 = this._b64arr.indexOf(input.charAt(i++));
			enc2 = this._b64arr.indexOf(input.charAt(i++));
			enc3 = this._b64arr.indexOf(input.charAt(i++));
			enc4 = this._b64arr.indexOf(input.charAt(i++));
			output.push((enc1 << 2) | (enc2 >> 4));
			if (enc3 !== 64) {
				output.push(((enc2 & 15) << 4) | (enc3 >> 2));
			}
			if (enc4 !== 64) {
				output.push(((enc3 & 3) << 6) | enc4);
			}
		}
		return output;
	};
}

woas.utf8 = {
	// encode from string to string
	encode: function(s) {
		return unescape( encodeURIComponent( s ) );
	},

	encode_to_array: function(s) {
		return woas.split_bytes( this.encode(s) );
	},
	decode: function(s) {
		return decodeURIComponent(escape(s));
	},
	decode_from_array: function(byte_arr) {
		try {
			return this.decode( woas.merge_bytes( byte_arr ) );
		}
		catch (e) {
			woas.log('ERROR - woas.utf8.decode_from_array: '+e);	//log:1
		}
		return null;
	},

	reUTF8Space: /[^\u0000-\u007F]+/g,

	// convert UTF8 sequences of the XHTML source into &#dddd; sequences
	do_escape: function(src) {
		return src.replace(this.reUTF8Space, function ($1) {
			var l=$1.length;
			var s="";
			for(var i=0;i < l;i++) {
				s+="&#"+$1.charCodeAt(i)+";";
			}
			return s;
		});
	}

};

// get path using file input control, or woas._last_filename if not available
// PVHL: rewrote; special knowledge (e.g. what opera and firefox can/can't do)
//   should be minimized where possible -- get_input_file_url knows how.
woas._get_path = function(id) {
	return this.dirname(this.get_input_file_url(id, true));
};

// tool to read/store flags in an integer
woas.bitfield = {
	// 32bit full mask
	_field_mask: [0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
				0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000,
				0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000,
				0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000],

	get: function(bm, pos) {
		return (bm & this._field_mask[pos]) ? true : false;
	},

	set: function(bm, pos, value) {
		if (value)
			return bm | this._field_mask[pos];
		return bm & ~this._field_mask[pos];
	},

	// return an integer after having parsed given object with given order
	get_object: function(obj, order) {
		var rv = 0;
		for(var i = 0; i < order.length; ++i) {
			if (obj[order[i]])
				rv |= this._field_mask[i];
		}
		return rv;
	},

	// set object properties to true/false after parsing the bits by given order
	set_object: function(obj, order, bm) {
		for(var i = 0; i < order.length; ++i) {
			obj[order[i]] = (bm & this._field_mask[i]) ? true : false;
		}
	}
};

// natural sorting algorithms by B.Huisman
// original algorithms by D.Koelle
// http://my.opera.com/GreyWyvern/blog/show.dml/1671288
woas.chunkify = function(t) {
    var tz = [], x = 0, y = -1, n = 0, i, j;

    while (i = (j = t.charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        tz[++y] = "";
        n = m;
      }
      tz[y] += j;
    }
    return tz;
};

woas.strnatcmp = function(a, b) {
  var	aa = woas.chunkify(a),
		bb = woas.chunkify(b);

  for (x = 0; aa[x] && bb[x]; x++) {
    if (aa[x] !== bb[x]) {
      var c = Number(aa[x]), d = Number(bb[x]);
      if (c == aa[x] && d == bb[x]) {
        return c - d;
      } else return (aa[x] > bb[x]) ? 1 : -1;
    }
  }
  return aa.length - bb.length;
};

/*
Array.prototype.natsort = function(caseInsensitive) {
  for (var z = 0, t; t = this[z]; z++) {
    this[z] = [];
    var x = 0, y = -1, n = 0, i, j;

    while (i = (j = t.charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        this[z][++y] = "";
        n = m;
      }
      this[z][y] += j;
    }
  }

  this.sort(function(a, b) {
    for (var x = 0, aa, bb; (aa = a[x]) && (bb = b[x]); x++) {
      if (caseInsensitive) {
        aa = aa.toLowerCase();
        bb = bb.toLowerCase();
      }
      if (aa !== bb) {
        var c = Number(aa), d = Number(bb);
        if (c == aa && d == bb) {
          return c - d;
        } else return (aa > bb) ? 1 : -1;
      }
    }
    return a.length - b.length;
  });

  for (var z = 0; z < this.length; z++)
    this[z] = this[z].join("");
}
*/

/*** src/loadsave.js ***/
// load modes which should be supported by load/save browser bindings
woas.file_mode = {
	UTF8_TEXT:		0,
	ASCII_TEXT:		1,
	DATA_URI:		2,
	BINARY:			3,
	BASE64:			4,
	UTF16_TEXT:		8
};

woas._guess_mime = function(filename) {
	var m=filename.match(/\.(\w+)$/);
	if (m===null) m = "";
	else m=m[1].toLowerCase();
	var guess_mime = "image";
	switch (m) {
		case "png":
		case "gif":
		case "bmp":
			guess_mime += "/"+m;
			break;
		case "jpg":
		case "jpeg":
			guess_mime = "image/jpeg";
			break;
	}
	return guess_mime;
};

// creates a DATA:URI from a plain content stream
woas._data_uri_enc = function(filename, ct, guess_mime) {
	if (typeof guess_mime != "string")
		guess_mime = this._guess_mime(filename);
	// perform base64 encoding
	return "data:"+guess_mime+";base64,"+this.base64.encode(ct);
};
woas._data_uri_enc_array = function(filename, arr, guess_mime) {
	if (typeof guess_mime != "string")
		guess_mime = this._guess_mime(filename);
	// perform base64 encoding
	return "data:"+guess_mime+";base64,"+this.base64.encode_array(arr);
};

// save the currently open WoaS
// PVHL: file_mode has to be UTF8, or Java saves in Windows with CRLF, except
//   Opera which saves LFCRLF. A note somewhere says some browsers can't do this
//   but I haven't been able to find one that doesn't. Which ones? Java should
//   be the same for all, and supported IE & FF can save UTF8 AFAIK. Will test
woas._save_this_file = function(new_data, old_data) {
	var filename = _get_this_filename();

	var r = woas.save_file(filename, this.file_mode.UTF8_TEXT, // was ASCII_TEXT
		this.DOCTYPE + this.DOC_START + "<"+"script woas_permanent=\"1\" type=\"tex"+"t/javascript\">"
		+ new_data + "\n" + old_data + "<"+"/html>");
	if (r)
		woas.log("NOTICE: \""+filename+"\" saved successfully");	// log:1
	else {
		var msg = this.i18n.SAVE_ERROR.sprintf(filename) + "\n\n";
		if (this.use_java_io) {
			// try to understand what went bad with Java
			if (typeof document.applets.TiddlySaver == "undefined")
				msg += this.i18n.NO_TIDDLY_SAVER+" "+this.i18n.TIDDLY_HELP;
			else if (typeof java == "undefined")
				msg += this.i18n.NO_JAVA+" "+this.i18n.TIDDLY_HELP;
			else
				msg += this.i18n.UNSPECIFIED_JAVA_ERROR;
		} else
			msg += woas.i18n.UNSUPPORTED_BROWSER.sprintf(navigator.userAgent);
		this.alert(msg);
	}
	return r;
};

//API1.0: save-file handler
//NOTE: save_mode is not always enforced by browser binding
woas.save_file = function(fileUrl, save_mode, content) {
	var r = null;
	// not bothering with Java failover - can't see need and needs testing
	// and proper error testing.
	if (this.browser.firefox) {
		r = this.mozillaSaveFile(fileUrl, save_mode, content);
	} else if (this.browser.ie) {
		r = this.ieSaveFile(fileUrl, save_mode, content);
	} else if (this.use_java_io) {
		r = this.javaSaveFile(fileUrl, save_mode, content);
	}
	if (r === null) {
		this.alert('Could not save "'+fileUrl+'"');
	}
	return r
};

var reDataUrlPfx = new RegExp("^data:\\s*([^;]*);\\s*base64,\\s*");
// get file content in FF3 without .enablePrivilege() (FBNil)
woas.mozillaLoadFileID = function(obj_id, load_mode, suggested_mime) {
	var obj = document.getElementById(obj_id);
	if(!window.Components || !obj.files)
		return null;
	var D=obj.files.item(0); // or: obj.files[0]; faster?
	if (D === null)
		return false;

	switch (load_mode) {
		case this.file_mode.DATA_URI:
			if (typeof suggested_mime != "string")
				return D.getAsDataURL();
			else // apply mime override
				return D.getAsDataURL().replace(/^data:(\s*)([^;]*)/, "data:$1"+suggested_mime);
			break;
		case this.file_mode.BASE64:
			return D.getAsDataURL().replace(reDataUrlPfx, '');
		case this.file_mode.BINARY:
			return D.getAsBinary();
		case this.file_mode.UTF8_TEXT:
			return D.getAsText("utf-8");
		case this.file_mode.UTF16_TEXT:
			return D.getAsText("utf-16");
		case this.file_mode.ASCII_TEXT:
			return D.getAsText("");
	}
	// not available
	this.crash(this.i18n.MODE_NOT_AVAIL.sprintf(load_mode.toString(16)));
	return null;
};

// see http://dev.w3.org/2006/webapi/FileAPI/
// PVHL: removed ... FileReaderSync interface doesn't work as this disabled code assumed
/*woas.ECMALoadFile = function(fileUrl, load_mode, suggested_mime) {*/

// API1.0: load-file handler
//
// Refactored by PVHL for FF7 breakdown. NOTE: FF7 broke because they went to standards.
// WoaS must be rewritten for asynchronous file read as this is the future standard;
// once done modern browsers will be able to read/write without Java -- including binary.
// Same probably true for write also -- haven't researched it yet.
//
// fileUrl is null if interactive read from file control.
// returns file contents, false if browser-specific (or java) load failed, or null
woas.load_file = function(fileUrl, load_mode, mime){
	// parameter consistency check
	if (typeof load_mode === "undefined") {
		woas.log("WARNING: No load mode specified, defaulting to UTF8_TEXT");
		// perhaps should be ASCII?
		load_mode = this.file_mode.UTF8_TEXT;
	}
	var r = null, g;
	if (fileUrl === null) {
		// try loading the file without using the path (if 3 < firefox < 7)
		// Firefox 7 has broken file reading with mozillaLoadFileID; use old method instead
		// Now uses gecko value for FF3-6; these version #s should be numeric
		if (this.browser.gecko) {
			g = Number(woas.browser.gecko.substr(0,3)); // false = 0
			if (g > 1.8 && g < 7) {
				r = this.mozillaLoadFileID("filename_", load_mode, mime);
				if (r !== null) { // mozillaLoadFileID worked (content or error)
					return r;
				}
			}
		}
		// retrieve fileUrl from input control 'filename_' (this shouldn't be hardwired)
		fileUrl = this.get_input_file_url();
		if (!fileUrl) return null; // user already warned
	}
	// can't see point of trying Java if IE/FF failed; if FF failed
	// we can't read the file path; IE fail is a security issue.
	// may look into this further, but needs a lot of testing.
	if (this.browser.gecko) { // old firefox load method; now FF7+ too
		r = this.mozillaLoadFile(fileUrl, load_mode, mime);
	} else if (this.browser.ie) {
		r = this.ieLoadFile(fileUrl, load_mode, mime);
	} else if (this.use_java_io) {
		// PVHL: this is now anything that is not IE or Firefox
		r = this.javaLoadFile(fileUrl, load_mode, mime);
	}
	if (r === null) {
		this.alert('Could not load "'+fileUrl+'"');
	}
	return r;
};

// the following load/save bindings will return:
// * null if they can't do it
// * false if there's an error
// * true if it saved OK
// * string with content if content was read successfully

// save through ActiveX
woas.ieSaveFile = function(filePath, save_mode, content) {
	var s_mode;
	switch (save_mode) {
		default:
/*		case this.file_mode.BINARY:
		case this.file_mode.DATA_URI:
		case this.file_mode.BASE64: */
			this.crash(this.i18n.MODE_NOT_AVAIL.sprintf(save_mode.toString(16)));
			return null;
		break;
		case this.file_mode.ASCII_TEXT:
			s_mode = 0; // ASCII
		break;
		case this.file_mode.UTF8_TEXT:
		case this.file_mode.UTF16_TEXT:
			s_mode = -1; // Unicode mode 
		break;
	}
	// first let's see if we can do ActiveX
	var fso;
	try	{
		fso = new ActiveXObject("Scripting.FileSystemObject");
	}
	catch (e) {
		return null;
	}
	try {
		var file = fso.OpenTextFile(filePath, 2, true, s_mode);
		file.Write(content);
		file.Close();
	}
	catch(e) {
		woas.log("ERROR: exception while attempting to save: " + e.toString());	// log:1
		return false;
	}
	return true;
};

// load through ActiveX
woas.ieLoadFile = function(filePath, load_mode, suggested_mime) {
	var o_mode;
	switch (load_mode) {
		//TODO: use Java applet for these modes
		//TODO: allow these modes when file is supposedly ASCII
/*		case this.file_mode.DATA_URI:
		case this.file_mode.BINARY:
		case this.file_mode.BASE64: */
		default:
			// not available
			this.crash(this.i18n.MODE_NOT_AVAIL.sprintf(load_mode.toString(16)));
			return null;
		case this.file_mode.ASCII_TEXT:
			o_mode = 0; // ASCII
		break;
		case this.file_mode.UTF16_TEXT:
		case this.file_mode.UTF8_TEXT:
			o_mode = -1; // Unicode
		break;
	}
	var fso, content = null;
	try	{
		fso = new ActiveXObject("Scripting.FileSystemObject");
	}
	catch (e) {
		woas.log('ERROR - woas.ieLoadFile: '+e);
		return null;
	}
	try {
		// attempt to open as unicode
		var file = fso.OpenTextFile(filePath,1,false,o_mode);
		content = file.ReadAll();
		file.Close();
	}
	catch(e) {
		woas.log("ERROR: exception while attempting to load\n\n" + e.toString());	// log:1
		return false;
	}
	// return a valid DATA:URI
/*	if (load_mode == this.file_mode.DATA_URI)
		return this._data_uri_enc(filePath, content, suggested_mime);
	else if (load_mode == this.file_mode.BASE64)
		return this.base64.encode(content); */
	return content;
};

// save through UniversalXPConnect
woas.mozillaSaveFile = function(filePath, save_mode, content) {
	if (!window.Components)
		return null;
	//FIXME: save_mode is not considered here
	try	{
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		file.initWithPath(filePath);
		if (!file.exists())
			file.create(0, 0664);
		else
			woas.log("NOTICE: file \""+filePath+"\" exists, overwriting");	// log:1
		var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
		out.init(file, 0x08 | 0x20 | 0x02, 0700, 0);
		out.write(content, content.length);
		out.flush();
		out.close();
	}
	catch(e) {
		woas.log("NOTICE: exception while attempting to save:\n\n" + e);	// log:1
		return(false);
	}
	return(true);
};

// load through UniversalXPConnect
woas.mozillaLoadFile = function(filePath, load_mode, suggested_mime) {
	// this is available on Mozilla browsers only
	if (!window.Components)
		return null;
	try	{
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		file.initWithPath(filePath);
		if (!file.exists()) {
			woas.log("NOTICE: unexisting file "+filePath);
			return false;
		}
		var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
		inputStream.init(file, 0x01, 04, 0);
		var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
		sInputStream.init(inputStream);
		if ( (load_mode == this.file_mode.UTF8_TEXT) ||
			 (load_mode == this.file_mode.ASCII_TEXT))
			return sInputStream.read(sInputStream.available());
		// this byte-by-byte read allows retrieval of binary files
		// PVHL: look at https://developer.mozilla.org/en/nsIScriptableInputStream;
		//   new capabilities for Gecko 2+ (FF4+) may allow efficient binary read.
		//   very simple but don't have time to test it right now; obviates need
		//   for array methods and merge_bytes use.
		var tot=sInputStream.available(), i=tot;
		var rd=[];
		while (--i >= 0) {
			var c=sInputStream.read(1);
			rd.push(c.charCodeAt(0));
		}
		if (load_mode == this.file_mode.BINARY)
			return(this.merge_bytes(rd));
		else if (load_mode == this.file_mode.DATA_URI)
			return this._data_uri_enc_array(filePath, rd, suggested_mime);
		else if (load_mode == this.file_mode.BASE64)
			return this.base64.encode_array(rd);
	}
	catch(e) {
		woas.log("NOTICE: exception while attempting to load:\n\n" + e);	// log:1
	}
	return false;
};

//FIXME: save_mode is not enforced
woas.javaSaveFile = function(filePath,save_mode,content) {
	if ((save_mode != this.file_mode.ASCII_TEXT) && (save_mode != this.file_mode.UTF8_TEXT)) {
		woas.log("Only ASCII and UTF8 file modes are currently supported with Java/TiddlySaver");	//log:1
		return null;
	}
	var encoding = (save_mode === this.file_mode.ASCII_TEXT) ? "" : "UTF-8";
	try {
		if(document.applets.TiddlySaver) {
			var rv = document.applets.TiddlySaver.saveFile(filePath, encoding, content);
			if (typeof rv == "undefined") {
				woas.log("Save failure, this is usually a Java configuration issue");
				return null;
			} else {
				return rv ? true : false;
			}
		}
	} catch(ex) {
		// report but check next method
		woas.log("TiddlySaver applet not available"); //log:1
	}
	// check if no JRE is available
	if (typeof java == "undefined") {
		woas.log("No JRE detected"); //log:1
		return null;
	}
	// try reading the file with java.io
	try {
		var s = new java.io.PrintStream(new java.io.FileOutputStream(filePath));
		s.print(content);
		s.close();
	} catch(ex) {
		woas.log("Failed reading file directly with Java: "+ex.toString());
		return false;
	}
	return true;
};

//FIXME: UTF8_TEXT/BINARY is not enforced here
woas.javaLoadFile = function(filePath, load_mode, suggested_mime) {
	if ((load_mode != this.file_mode.ASCII_TEXT) && (load_mode != this.file_mode.UTF8_TEXT)) {
		woas.log("Only ASCII and UTF8 file modes are currently supported with Java/TiddlySaver");	//log:1
		return null;
	}
	var encoding = (load_mode === this.file_mode.ASCII_TEXT) ? "" : "UTF-8",
		content = null;
	try {
		if(document.applets.TiddlySaver) {
			content = document.applets.TiddlySaver.loadFile(filePath, encoding);
			if (content === null) {
				woas.log("Load failure, maybe file does not exist? "+filePath); //log:1
				return false;
			}
			// check that it is not an "undefined" string
			if (typeof content == "undefined") {
				woas.log("Load failure, this is usually a Java configuration issue"); //log:1
				return null;
			}
			// convert to string only after checking that it was successfully loaded
			content = String(content);
			if (load_mode == this.file_mode.DATA_URI)
				return this._data_uri_enc(filePath, content, suggested_mime);
			else if (load_mode == this.file_mode.BASE64)
				return this.base64.encode(content);
			return content;
		}
	} catch(ex) {
		// report but check next method
		woas.log("TiddlySaver applet not available"); //log:1
	}
	// check if no JRE is available
	if (typeof java == "undefined") {
		woas.log("No JRE detected"); //log:1
		return null;
	}
	content = "";
	var r, line;
	try {
		r = new java.io.BufferedReader(new java.io.FileReader(filePath));
		while((line = r.readLine()) !== null)
			content += new String(line) + "\n";
		r.close();
	} catch(ex) {
		woas.log("Exception in javaLoadFile(\""+filePath+"\"): "+ex);
		return false;
	}
	if (load_mode == this.file_mode.DATA_URI)
		return this._data_uri_enc(filePath, content, suggested_mime);
	else if (load_mode == this.file_mode.BASE64)
		return this.base64.encode(content);
	return content;
};

function printout_arr(arr, split_lines) {

	function elem_print(e) {
		return "'" + woas.js_encode(e, split_lines) + "'";
	}

	var il = arr.length, i, s;
	if (!il) { return "" }
	s = elem_print(arr[0]);
	for (i = 1; i < il; i++) {
		s += ",\n" + elem_print(arr[i]);
	}
	return s + "\n";
}

function printout_mixed_arr(arr, split_lines, attrs) {

	function elem_print(e, attr) {
		if (attr & 2) {
			return "[" + e.join(',') + "]";
		}
		return "'" + woas.js_encode(e, split_lines) + "'";
	}

	var il = arr.length, i, s;
	if (!il) { return "" }
	s = elem_print(arr[0], attrs[0]);
	for (i = 1; i < il; i++) {
		s += ",\n" + elem_print(arr[i], attrs[i]);
	}
	return s + "\n";
}

// used to print out encrypted page bytes and attributes
// PVHL: removed encoding; tests show it is not shorter to encode
//  but must take a lot more time to produce; replacing in save;
//  leaving in in case others are using it
function printout_num_arr(arr) {
	// works fine with empty array
	return arr.join(',');
}

function printout_fixed(elem, n) {
	return n ? elem + ("," + elem).repeat(n - 1) : '';
}

// save full WoaS to file
woas._save_to_file = function(full) {
	this.progress_init("Saving to file");

	// force full mode if WSIF datasource mode changed since last time loading/saving
	var ds_changed = (this.config.wsif_ds !== this._old_wsif_ds),
	// increase the marker only when performing full save
		new_marker = ((full | ds_changed) && !this.config.wsif_ds.length) ? this._inc_marker(__marker) : __marker,
		safe_current;

	// setup the page to be opened on next start
	if (this.config.nav_history) {
		if (!this.page_exists(current))
			safe_current = this.config.main_page;
		else safe_current = current;
	} else
		safe_current = this.config.main_page;
	
	// output the javascript header and configuration flags
	var computed_js = "\n/* <![CDATA[ */\n\n/* "+new_marker+"-START */\n\nvar woas = {\"version\": \""+this.version+
	"\"};\n\nvar __marker = \""+new_marker+"\";\n\nwoas[\"config\"] = {";
	for (var param in this.config) {
		computed_js += "\n\""+param+"\":";
		switch(typeof(this.config[param])) {
			case "boolean":
				computed_js += (this.config[param] ? "true" : "false")+",";
			break;
			case "string":
				computed_js += "'"+this.js_encode(this.config[param])+"',";
			break;
			default: // for numbers
				computed_js += this.config[param]+",";
			break;
		}
	}
	computed_js = computed_js.substr(0,computed_js.length-1);
	computed_js += "};\n";
	
	computed_js += "\nvar current = '" + this.js_encode(safe_current)+"';\n\n";
	
	computed_js += "var backstack = [\n" + printout_arr(this.config.nav_history ? backstack : [], false) + "];\n\n";
	
	// in WSIF datasource mode we will save empty arrays
	if (this.config.wsif_ds.length !== 0)
		computed_js += "var page_titles = [\n];\n\n";
	else
		computed_js += "var page_titles = [\n" + printout_arr(page_titles, false) + "];\n\n";
	
	computed_js += "/* " + new_marker + "-DATA */\n";

	if (full || ds_changed) {
		this._old_wsif_ds = this.config.wsif_ds;
		if (this.config.wsif_ds.length) {
			// everything empty when the javascript layer is not used
			computed_js += "var page_attrs = [];\n\n";
			computed_js += "var page_mts = [];\n\n";
			computed_js += "var pages = [\n];\n\n";
		} else {
			computed_js += "var page_attrs = [" + page_attrs.join(',') + "];\n\n";
			computed_js += "var page_mts = [" + (this.config.store_mts ? page_mts.join(',') : "0,".repeat(page_mts.length-1)+"0") + "];\n\n";
			computed_js += "var pages = [\n" + printout_mixed_arr(pages, this.config.allow_diff, page_attrs) + "];\n\n";
		}
		computed_js += "/* " + new_marker + "-END */\n";
	}

	// cleanup the DOM before saving
	var bak_tx = this.getHTMLDiv(d$("woas_page")),
		bak_mn = this.getHTMLDiv(d$("woas_menu")),
		bak_mts = this.getHTMLDiv(d$("woas_mts")),
		bak_mts_shown = !this.ui.display("no_mts"),
		bak_wait_text = this.getHTML(d$("woas_wait_text")),
	// clear titles and css as well as they will be set on load.
		bak_title = this.getHTMLDiv(d$("woas_title"));

	d$("woas_editor").value = "";
	this.setHTMLDiv(d$("woas_page"), "");
	this.setHTMLDiv(d$("woas_menu"), "");
	this.setHTMLDiv(d$("woas_mts"), "");
	this.setHTMLDiv(d$("woas_title"), "");

	// set the loading message
	this.setHTML(d$("woas_wait_text"), this.i18n.LOADING);
	// temporarily display such message
	this.ui.display({"wait": true});
	var bak_cursor = document.body.style.cursor;
	document.body.style.cursor = "auto";

	var data = this._extract_src_data(__marker, document.documentElement.innerHTML, full || ds_changed, safe_current);
	
	// data is ready, now the actual save process begins
	var r = false;
	this.ui.display({"wait": false});
	this.setHTML(d$("woas_wait_text"), bak_wait_text);
	document.body.style.cursor = bak_cursor;

	//DEBUG check
	if (data.length === 0) {
		this.crash("Could not retrieve original DOM data!");
	} else {
	
//	if (!this.config.server_mode || (was_local && this.config.server_mode)) {
	if (!this._server_mode)
		r = this._save_this_file(computed_js, data);
//		was_local = false;
//	}

	// save was successful - trigger some events
	if (r) {
		this.after_config_saved();
		if (full)
			this.after_pages_saved();
	}
	} //DEBUG check

	this.setHTMLDiv(d$("woas_page"), bak_tx);
	this.setHTMLDiv(d$("woas_menu"), bak_mn);
	this.setHTMLDiv(d$("woas_mts"), bak_mts);
	this.setHTMLDiv(d$("woas_title"), bak_title);
	
	//TODO: re-run after parsing hooks
	// would fix issues with import page for example
	
	this.progress_finish();
	
	return r;
};

// make sure self-closing tags are actually closed
function reXHTMLFix_hook(str, tag) {
	var l=str.length;
	if (str.charAt(l-1)!=='/')
		str = str.substr(0, l-1)+" />";
	return str;
}
var reXHTMLFix = /<(img|hr|br|input|meta)[^>]*>/gi;

var reHeadTagEnd = new RegExp("<\\/"+"head[^>]*>", "ig"),
	reHeadTagStart = new RegExp("<"+"head[^>]*>", "ig"),
	reTagStart = /<(\w+)([^>]*)>/g,
	reTagEnd = /<\/(\w+)[^>]*>/g,
	reEditorTA = new RegExp('<'+'textarea\\s+id="?woas_editor"?\\s*[^>]+>(.*?)<'+'/textarea>', 'gi');

woas._extract_src_data = function(marker, source, full, current_page, data_only) {
	var e_offset, s_offset;
	// find the start marker for safety checking
	s_offset = source.indexOf("/* "+marker+ "-START */");
	if (s_offset === -1) {
		this.alert(this.i18n.ERR_MARKER.sprintf("START"));
		return false;
	}			
	// find the end marker, necessary to make some DOM/XHTML fixes
	e_offset = source.indexOf("/* "+marker+ "-END */", s_offset);
	if (e_offset === -1) {
		this.alert(this.i18n.ERR_MARKER.sprintf("END"));
		return false;
	}
	// properly update offset (+2 is for newlines)
	e_offset += 3 + marker.length + 7 + 2;
	
	// used during import
	if (full && data_only) {
		return source.substring(s_offset, e_offset);
	}

	reHeadTagStart.lastIndex = 0;
	var head_start, head_end,
		m = reHeadTagStart.exec(source);
	if (m !== null)
		head_start = m.index+m[0].length;
	else {
		this.crash("Cannot find head start tag");
		return false;
	}
	// search for head end tag starting at data end offset
	reHeadTagEnd.lastIndex = e_offset;
	m = reHeadTagEnd.exec(source);
	if (m !== null)
		head_end = m.index + m[0].length;
	else {
		this.crash("Cannot find head end tag");
		return false;
	}
	
	// filter out the unimportant tags from head
	// build a list of replacements with offsets
	
	// first take away the head
	var needle, m2, l_attrs, the_head = source.substring(0, head_end),
		splicings = [], tag_end,
		// rest_of_source is everything from the body tag to the end
		rest_of_source = source.substring(head_end);
	// reset big string
	source = "";
	// skip non-head content
	reTagStart.lastIndex = head_start;
	
	m = reTagStart.exec(the_head);
	while (m !== null) {
		tag = m[1].toLowerCase();
		var broken=false;
		switch (tag) {
			case "script":
			case "style":
			case "title":
				reTagEnd.lastIndex = m.index + m[0].length;
				do {
					m2 = reTagEnd.exec(the_head);
					if (m2 === null) {
						woas.log("found "+m[1]+" without closing tag");
						// continue to check for permanent attribute
						broken = true;
						break;
					}
					close_tag = m2[1].toLowerCase();
				} while (close_tag !== tag);
				// fallback wanted to set tag end like if it was a single tag
				if (!broken) {
					tag_end = tag_end = m2.index+m2[0].length;
					break;
				}
			case "meta":
				tag_end = m.index+m[0].length;
				break;
			default:
//				woas.log("Unknown tag in head: "+tag);
				// continue to check for permanent attribute
				tag_end = m.index+m[0].length;
				broken = true;
			break;
		}

		l_attrs = m[2].toLowerCase();
		// this was marked as permanent tag
		var was_replaced = false;
		if (l_attrs.indexOf("woas_permanent=")!==-1) {
			if (!broken) {
			if (tag === "style") {
				was_replaced = true;
				if (l_attrs.indexOf("woas_core_style=")!==-1) {
//					woas.log("Replacing CSS");
					needle = m[0]+woas.get_text("WoaS::CSS::Boot")+m2[0];
				} // else leave as-is
			} else if (tag === "title") {
//				woas.log("Replacing title");
				needle = m[0]+woas.xhtml_encode(current_page)+m2[0];
				was_replaced = true;
			}
			}
			// will leave tag untouched
		} else {
//			woas.log("Removing tag "+tag);
			needle = "";
			was_replaced = true;
		}
		if (was_replaced)
			// add this splicing
			splicings.push( { start: m.index, end: tag_end, needle: needle } );
		reTagStart.lastIndex = tag_end;
		m = reTagStart.exec(the_head);
	}

	// rebuild the source by using splicings
	if (splicings.length) {
		var prev_ofs = 0;
		for(var i=0;i < splicings.length;++i) {
			source += the_head.substring(prev_ofs, splicings[i].start) + splicings[i].needle;
			prev_ofs = splicings[i].end;
		} splicings = null;

		// XHTML hotfixes (FF doesn't either save correctly)
		source += the_head.substr(prev_ofs); the_head = null;
		
		// re-calculate offsets
		
		// find the start marker for safety checking
		s_offset = source.indexOf("/* "+marker+ "-START */");
		if (s_offset === -1) {
			this.alert(this.i18n.ERR_MARKER.sprintf("START"));
			return false;
		}			
		// find the end marker, necessary to make some DOM/XHTML fixes
		e_offset = source.indexOf("/* "+marker+ "-END */", s_offset);
		if (e_offset === -1) {
			this.alert(this.i18n.ERR_MARKER.sprintf("END"));
			return false;
		}
		// properly update offset (+2 is for newlines)
		e_offset += 3 + marker.length + 7 + 2;
	} else {
		source = the_head;
		the_head = null;
	}
	
// PVHL: simplest fix for multiple Chrome induced problems is to just find the
//       last script closing tag and fix the end of the markup. Saves a lot of
//       code! IE makes all the tags uppercase!
	var last_script = rest_of_source.lastIndexOf('<'+'/script>');
	if (last_script === -1) last_script = rest_of_source.lastIndexOf('<'+'/SCRIPT>'); // IE
	rest_of_source = rest_of_source.substring(0, last_script) + '<'+'/script>\n<'
					+ 'div id="woas_custom_accesskeys">&'+'nbsp;<'+'/div>\n<'+'/body>';

	// replace textarea with a standard one
	source += rest_of_source
			.replace(reEditorTA, '<'+'textarea id="woas_editor" rows="0" cols="0">&'+'nbsp;<'+'/textarea>')
	// XHTML hotfixes (FF2/FF3 doesn't either save correctly)
			.replace(reXHTMLFix, reXHTMLFix_hook);
	rest_of_source = null;
	if (!full) {
		e_offset = source.indexOf("/* "+marker+ "-DATA */", s_offset);
		if (e_offset === -1) {
			this.alert(this.i18n.ERR_MARKER.sprintf("DATA"));
			return false;
		}
		e_offset += 3 + marker.length + 8 + 1 /* newlines */;
	}
	return source.substring(e_offset);
};

// increment the save-counter portion of the marker
var reMarker = /([^\-]*)\-(\d{7,7})$/;
woas._inc_marker = function(old_marker) {
	var m = old_marker.match(reMarker);
	if (m===null)
		return _random_string(10)+"-0000001";
	var n = new Number(m[2].replace(/^0+/, '')) + 1;
	n = n.toString();
	// marker part + 0-padded save count number
	return m[1]+"-"+String("0").repeat(7-n.length)+n;
};

// load URL via XHR
woas.remote_load = function(url) {
	var HttpReq = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
	HttpReq.open('GET', url, false);
	HttpReq.setRequestHeader('Content-Type', 'text/plain');
	HttpReq.send(null);
	return HttpReq.responseText;
};

/*** src/parser.js ***/
// module @parser
woas.parser = {

render_title: null, // title of page being rendered
has_toc: null,
toc: [],
force_inline: false, // stops layout being broken when presenting search results
inline_tags: 0,
_parsing_menu: false, // true when we are parsing the menu page

// properties used by _transclude
_MAX_TRANSCLUSION_RECURSE: 256,
_transcluding: 0,
_snippets: null,
_export_links: null,

// a variety of regular expressions used by the parser

// these REs look for one optional (dynamic) newline at the end
reComments: /<\!--([\s\S]*?)-->([ \t]*\n)?/g,
reMacros: /<<<([\s\S]*?)>>>([ \t]*\n)?/g,
reNowiki: /\{\{\{([ \t]*\n)?([\s\S]*?)(\n[ \t]*)?\}\}\}([ \t]*\n)?/g,
reScripts: new RegExp("<"+"script([^>]*)>([\\s\\S]*?)<"+"\\/script>([ \\t]*\\n)?", "gi"),
reStyles: new RegExp("<"+"style([^>]*)>[\\s\\S]*?<"+"\\/style>([ \\t]*\\n)?", "gi"),
reTOC: /\[\[Special::TOC\]\]([ \t]*\n)?/,

// REs without optional newline search
// reAutoLinks finds sequences that look like URLs (x://)
reAutoLinks: /(?:(https?|ftp|file)|[a-zA-Z]+):\/\/(?:[^\s]*[^\s*.;,:?!\)\}\]])*/g,
// stops automatic br tag generation for listed tags
reBlkHtml: /^(p|div|br|blockquote|[uo]l|li|table|t[rhd]|tbody|thead|h[1-6r]|center)$/i,
reDry: /(\{\{\{[\s\S]*?\}\}\}|<<<[\s\S]*?>>>|<\!--[\s\S]*?-->)/g,
reHasDNL: /^([ \t]*\n)/,
// DEPRECATED "!" syntax is supported but will be removed soon
reHeading: /^([\!=]{1,6})[ \t]*(.*?)[ \t]*(?:\1?)$/gm,
reHtml: /([ \t]*)((?:(?:[ \t]*)?<\/?([^<\/\s>]+)[^<>]*>)+)([ \t]*\n)?/g,
reListReap: /^([\*#@])[ \t].*(?:\n\1+[ \t].+)*/gm,
reListItem: /^([\*#@]+)[ \t]([^\n]+)/gm,
// tags that can have an optional newline before before/after them
reNewlineBefore: /\n(<(?:[uo]l).*?>)/g,
reNewlineAfter: /(<\/(?:h[1-6]|[uo]l)>)\n/g,
reReapTablesNew: /^\{\|(.*)((?:\n\|.*)*)$/gm,
reReapTablesNewSub1: /\n\|([+ \t-\|])(.*)/g,
reReapTablesNewSub2: /(\|\|)(\s{0,1})(\s?)(?=\|\|)/g,
reReapTablesNewSub3: /(\|\|\s*)$/,
reReapTablesNewSub4: /\|\|\t/g,
reReapTablesNewSub5: /\t\|\|/g,
reReapTablesHead: /^(\s*)(?:(=+)\s*)?(.*?)(\s*)$/,
// rulers with 3 hyphens DEPRECATED (should be 4 or more: ----)
// only white space is allowed before/after the hyphens
reRuler: /^[ \t]*\-{3,}[ \t]*$/gm,
reTransclusion: /\[\[Include::([\s\S]+?)\]\]/g,
reWikiLink: /\[\[(.*?)(?:\|(.*?))??\]\]/g,

// xhtml output strings
_HR: "<"+"hr class=\"woas_ruler\" />",

// extract the wiki tags from a wiki URL
_get_tags: function(text, last_tag) {
	var tags = [];
	// remove the starting part
	if (text.substr(0, 5) === "Tag::")
		text = woas.trim(text.substring(5));
	else if (text.substr(0,6)==="Tags::") {
//		woas.log("Using deprecated 'Tags' namespace");
		text = woas.trim(text.substring(6));
	} else // not a valid tagging
		return tags;
	// check length only after having removed the part we don't need
	if (!text.length)
		return tags;
	var alltags = this.split_tags(text), tag;
	if (last_tag !== null) alltags = alltags.concat(this.split_tags(last_tag));
	for(var i=0;i < alltags.length;i++) {
		tag = woas.trim(alltags[i]);
		if (tag.length && tags.indexOf(tag) === -1)
			tags.push(tag);
	}
	return tags;
},

_init: function() {
	this.marker = _random_string(3) + ":" + _random_string(3);
	this.reBaseSnippet = new RegExp(this.marker + "(\\d+);", "g");
	this.NL_MARKER = this.marker + "NL;";
	this.reNL_MARKER = new RegExp(this.marker + "NL;([ \\t]*\\n)?", "g");
},

// create a preformatted block ready to be displayed
_make_preformatted: function(text, add_style) {
	var cls, tag, p = text.indexOf("\n");
	if (p !== -1) {
		// remove the first newline to be compliant with old parsing
		if (p === 0) { text = text.substr(1); }
		cls = " woas_nowiki_multiline";
		tag = "pre";
	} else {
		cls = "woas_nowiki";
		tag = "tt";
	}
	return this._raw_preformatted(tag, text, cls, add_style);
},

_raw_preformatted: function(tag, text, cls, add_style) {
	add_style = add_style ? ' style="' + add_style + '"' : '';
	// PVHL: IE can't do pre without windows newlines
	if (woas.browser.ie) {
		text = text.replace(/\n/g, '\r\n');
	} else {
	}
	return "<" + tag + " class=\"" + cls + "\"" + add_style + ">" +
		woas.xhtml_encode(text) + "</"+tag+">";
},

// render a single wiki link
_render_wiki_link: function(target, label, snippets, tags, export_links) {
	if (label === undefined) {
		label = '';
	}
	var page = woas.title_unalias(target), // apply aliases to page title
		hashloc = page.indexOf('#'),
		r_label = (label === '') ? page : label,
		title = '', gotohash = '', str, wl, pg,
		sLink = '<'+'a class="%s" title="%s"%s>%s<'+'\/a>',
		sLinkBroken = '<'+'span class="woas_broken_link">%s<'+'\/span>',
		scWorld = 'woas_world_link', scWoas = 'woas_link', scWoasUn = 'woas_unlink',
		sHref = ' href="%s"', sHrefTrgt = ' href="%s" target="_blank"',
		sOnClick = ' onclick="woas.go_to(\'%s\')"';

	// check for tag definitions if they might exist
	if (page.match('Tag') && typeof tags === 'object') {
		var found_tags = this._get_tags(page, label);
		if (found_tags.length > 0) {
			// do not use concat because 'tags' is passed byref
			for(var i = 0, it = found_tags.length; i < it; ++i) {
				tags.push(found_tags[i]);
			}
			if (!this.force_inline)
				return '';
			++this.inline_tags;
			return woas.parser.marker + 'T' + inline_tags + ';';
		}
	}

	// check for protocol links
	if (page.match(/^\w+:\/\//)) {
		// convert mailto:// to mailto:
		page = page.replace(/^mailto:\/\//, 'mailto:');
		// always give title attribute
		str = sLink.sprintf(scWorld, woas.xhtml_encode(page), sHrefTrgt.sprintf(page), r_label);
		return woas.parser.place_holder(snippets, str);
	}

	// create section heading info
	if (hashloc !== -1) {
		gotohash = this.heading_anchor(page.substr(hashloc + 1), true);
		pg = page.substr(0, hashloc);
	} else {
		pg = page;
	}
	if (!pg && !gotohash || /"/.test(pg)) {
		// PVHL: " will break link - current code does not allow.
		//  empty link - [[#]] ?
		return woas.parser.place_holder(snippets,
			'[[<'+'span style="color:#f00">'+target+'<'+'/span>'+
			(label ? '|'+label : '')+']]');
	}
	// create a title attribute only when page URI differs from page title
	if (label !== '' || gotohash) {
		title = woas.xhtml_encode(page);
	}

	if ((!pg && gotohash) || woas.page_exists(pg)) { // normal page
		if (export_links) {
			wl = woas.exporter._get_fname(pg);
			if (wl === '#') {
				return woas.parser.place_holder(snippets, sLinkBroken.sprintf(r_label));
			}
			wl = sHref.sprintf(wl + (gotohash ? '#' + gotohash : ''));
		} else {
			wl = sOnClick.sprintf(woas.js_encode(pg) + (gotohash ? '#' + woas.js_encode(gotohash) : ''));
		}
		str = sLink.sprintf(scWoas, title, wl, r_label);
	} else { // page does not exist
		if (export_links) {
			str = sLinkBroken.sprintf(r_label);
		} else {
			wl = sOnClick.sprintf(woas.js_encode(pg));
			str = sLink.sprintf(scWoasUn, title, wl, r_label);
		}
	}
	return woas.parser.place_holder(snippets, str);
},

_transclude: function (str, $1, img_gallery) {
	var that = woas.parser,
		parts = $1.split("|"),
		templname = parts[0],
		is_emb = false, ns = woas.get_namespace(templname, true),
		// temporary page object
		P = { body: null };
	//woas.log("Transcluding "+templname+"("+parts.slice(0).toString()+")");	// log:0
	// increase transclusion depth (used by namespace listing)
	++that._transcluding;
	if (woas.is_reserved(templname) || (templname.substring(templname.length - 2) === "::"))
		P.body = woas.get_text_special(templname);
	else {
		var epi = woas.page_index(templname);
		// offer a link for uploading, to implement feature as before 0.11.0
		if (epi == -1)
			P.body = "[<!-- -->[Include::[["+templname+"]]]]";
		else {
			P.body = woas.get__text(epi);
			is_emb = woas.is_embedded(templname);
		}
	}
	// template retrieval error
	if (P.body === null) {
		--that._transcluding;
		if (img_gallery) {
			// stop double message for encrypted image
			return that.place_holder(that._snippets, that.render_error('[<!-- -->'
				+str.substr(1), "#8709")+'\n');
		}
		// show an error with empty set symbol
		return that.place_holder(that._snippets, that.render_error(str, "#8709"));
	}
	// add the inline file/image if embedded
	if (is_emb) {
	//woas.log("Embedded file transclusion: "+templname);	// log:0
		if (woas.is_image(templname)) {
			var img, img_name = woas.xhtml_encode(templname.substr(templname.indexOf("::")+2)),
				img_cls;
			img_cls = img_gallery ? 'woas_img_list' : 'woas_img';
			if (that._export_links) {
				// check that the URI is valid
				var uri=woas.exporter._get_fname(templname);
				if (uri == '#')
					img = that.render_error(templname, "#8709");
				else
					img = "<" + "img class=\""+img_cls+"\" src=\"" + uri + "\" alt=\"" + img_name + "\" ";
			} else
				img = "<" + "img class=\""+img_cls+"\" src=\"" + P.body + "\" ";
			if (parts.length > 1) {
				img += parts[1];
				// always add the alt attribute to images
				if (!that._export_links && !parts[1].match(/alt=('|").*?\1/))
					img += " alt=\"" + img_name + "\"";
			}
			P.body = img + " />";
		} else { // embedded file but not image
			if ((parts.length > 1) && (parts[1] == "raw"))
				P.body = woas.base64.decode(P.body);
			else
				P.body = "<"+"div class=\"woas_embedded\">"+
						woas.xhtml_encode(woas.base64.decode(P.body))+"<"+"/div>";
		}
		P.body = that.place_holder(that._snippets, P.body);
	} else { // not embedded
		// process nowiki, macros, and XHTML comments
		that.pre_parse(P, that._snippets);
		// finally replace transclusion parameters
		if (parts.length) {
			P.body = P.body.replace(/%\d+/g, function(str) {
				var paramno = parseInt(str.substr(1));
				return paramno < parts.length ? parts[paramno] : str;
			});
		}
	}
	--that._transcluding;
	return P.body;
},

// @override to apply some further customization before parse output
after_parse: function(P) {
},

// remove comment/nowiki/macro blocks while renaming pages (no dynamic newlines)
dry: function(P, NP, snippets) {
	NP.body = P.body.replace(this.reDry, function (str) {
		return woas.parser.place_holder(snippets, str);
	});
},

// @override to parse further syntax before final replace
extend_syntax: function(P) {
},


// Create a W3C-spec-legal ID from heading using quick & simple hash.
// The same string produces the same hash, so headings need to be unique
//   or the first match will be moved to (could add editor alert).
// 's' is heading text; should not be empty, straight unicode text - no HTML
// 'check' (optional) forces test for already transformed anchor
heading_anchor: function(s, check) {
	if (!s || check && /^S\d+$/.test(s)) {
		return s;
	}
	var id = 0, i = 0, il;
	for (il = s.length; i < il;) {
		id += s.charCodeAt(i) * ++i;
	}
	return 'S' + id;
},

import_disable: function(NP, js, macros) {
	var that = this, snippets = [];
	// put away nowiki blocks - XHTML comments now allowed in macros
	NP.body = NP.body.replace(this.reNowiki, function (str, $1, dynamic_nl) {
			return that.place_holder_dnl(snippets, str, dynamic_nl);
	});
	if (js)
		NP.body = NP.body.replace(this.reScripts, "<"+"disabled_script$1>$2<"+"/disabled_script>$3");
	if (macros) {
		NP.body = NP.body.replace(this.reMacros, function(str, $1, $2) {
			if (typeof $1 === 'undefined') { $1 = ''; } // IE
			if (typeof $2 === 'undefined') { $2 = ''; }
			return '<<< Macro disabled\n' + $1 + '>>>' + $2;
		});
	}
	// clear dynamic newlines
	NP.body = NP.body.replace(this.reNL_MARKER, "");
	// restore everything
	this.undry(NP, snippets);
	snippets = null;
},

// 'text' is the raw wiki source
// 'export_links' is set to true when exporting wiki pages (used to generate proper href for hyperlinks)
// 'js_mode' controls javascript behavior. Allowed values are:
//    0 - leave script tags as they are (used for exporting; acts much like mode 2)
//    1 - place script tags in head (dynamic),
//    2 - re-add script tags after parsing
//    3 - convert script tags to nowiki blocks
// @override to customize parsing (see also woas.parser.after_parse and woas.pager.browse
parse: function(text, export_links, js_mode) {
	if (woas.config.debug_mode) {
		if ((typeof text).toLowerCase() != "string") {
			woas.crash("Called parse() with invalid argument: "+(typeof text));	// log:1
			return null;
		}
	}
	// default fallback
	if (typeof export_links == "undefined")
		export_links = false;
	if (typeof js_mode == "undefined")
		js_mode = 1;

	var that = this, pLength, tags = [],
		snippets = [], // HTML markup removed from further parsing
		backup_hook = this.after_parse,
		P = { body: text }; // allow passing text by reference
	text = null;

	// make a backup copy of current macros, so no new macros remain after page processing
	woas.macro.make_backup();

	// process nowiki, macros, and XHTML comments
	this.pre_parse(P, snippets);

	// transclude pages (templates)
	if (!this.force_inline) {
		// apply transclusion syntax
		this.transclude_syntax(P, snippets, export_links);
	}

	// PVHL: code was breaking exported scripts by adding br tags; refactored
	if (js_mode) {
		// reset the array of custom scripts for the correct target
		var script_target = this._parsing_menu ? "menu" : "page";
		woas.scripting.clear(script_target);
	}
	// gather all script tags
	P.body = P.body.replace(this.reScripts, function (str, $1, $2, dynamic_nl) {
		if (js_mode === 0 || js_mode === 2) {
			return that.place_holder_dnl(snippets, str, dynamic_nl);
		} else if (js_mode === 3) {
			// during safe mode do not activate scripts, transform them to nowiki blocks
			return that.place_holder_dnl(snippets, that._make_preformatted(
				woas.i18n.JS_DISABLED + str, 'border:1px solid #f00'), dynamic_nl);
		} // else
		var m = $1.match(/src=(?:"|')([^\s'">]+)/),
			external = (m!==null);
		woas.scripting.add(script_target, external ? m[1] : $2, external);
		return "";
	});

	// take away style blocks
	P.body = P.body.replace(this.reStyles, function(str, $1, dynamic_nl) {
		return that.place_holder_dnl(snippets, str, dynamic_nl);
	});

	// put a placeholder for the TOC (including dynamic newline)
	this.has_toc = false;
	P.body = P.body.replace(this.reTOC, function(str, dnl) {
		that.has_toc = true;
		if (typeof dnl === "undefined") dnl = ""; // IE
		else if (dnl !== "") dnl = that.NL_MARKER + dnl;
		return that.marker + "TOC" + dnl;
	});

	// wiki tags
	this.inline_tags = 0;

	// static syntax parsing
	this.syntax_parse(P, snippets, tags, export_links, this.has_toc);

	// restore macros to those already defined before page was parsed
	woas.macro.remove_backup();

	// sort tags at bottom of page if set in config
	tags = tags.toUnique();
	if (woas.config.sort_tags) { tags = tags.sort(); }
	if (tags.length && !export_links) {
		var s;
		if (this.force_inline)
			s = "";
		else
			s = "<"+"div class=\"woas_taglinks\">";
		s += "Tags:";
		for(var i=0;i < tags.length;++i) {
			s += " <"+"a onclick=\"woas.go_to('Tagged::"+woas.js_encode(tags[i])+"')\">"+
				woas.xhtml_encode(tags[i])+"<"+"/a>";
		}
		if (this.force_inline) { // re-print the inline tags (works only on last tag definition?)
			P.body = P.body.replace(new RegExp(this.marker + "T(\\d+);", "g"), function (str, $1) {
				// loose comparison is OK here
				if ($1 == that.inline_tags)
					return s;
				return "";
			});
			this.force_inline = false;
		} else {
			s+="<"+"/div>";
			P.body += s;
		}
	}

	// syntax parsing has finished; apply any final changes
	if (this.after_parse === backup_hook)
		this.after_parse(P);

	// finished
	return P.body;
},

// XHTML lists and tables parsing code by plumloco
// There is no limit to the level of nesting and produces valid XHTML markup
// Refactored by PVHL to avoid some string copying and incorporate sublist
// (can be improved further by pushing strings to array and joining at end)
parse_lists: function(str, type) {
	function sublist(lst, ll, type) {
		if (!lst.length)
			return '';
		if (lst[0][1].length > ll)
			return sublist(lst, ll + 1, type);
		var item, subl, s = '';
		while (lst[0][1].length == ll ) {
			item = lst.shift();
			subl = sublist(lst, ll + 1, type);
			if (subl.length)
				s += lst_item.sprintf(item[2] + lst_type[type].sprintf(subl));
			else
				s += lst_item.sprintf(item[2]);
			if (!lst.length)
				break;
		}
		return s;
	};

	var lst_item = '<'+'li>%s<'+'/li>' + woas.parser.NL_MARKER + '\n',
		lst_type = [
			'<'+'ul>%s<'+'/ul>' + woas.parser.NL_MARKER,
			'<'+'ol>%s<'+'/ol>' + woas.parser.NL_MARKER,
			'<'+'ol type="a">%s<'+'/ol>' + woas.parser.NL_MARKER
		],
		stk = []; // collect all items in a stack
	type = "*#@".indexOf(type);
	if (type === -1) return; // shouldn't be possible
	str.replace(woas.parser.reListItem, function(str, p1, p2) {
		stk.push([str, p1, p2]);
	});
	return lst_type[type].sprintf(sublist(stk, 1, type));
},

// put away stuff contained in user-defined macro blocks
// PVHL: needs more refactoring; pass snippets to macro? Returned
//   text should not need more processing
//   m.block flags removal of dnl; being tested as a possible remedy
//   for some formatting issues (works well, but undocumented at present;
//   there is probably a better way to do this though).
parse_macros: function(P, snippets) {
	var that = this;
	P.body = P.body.replace(this.reMacros, function (str, $1, dynamic_nl) {
		dynamic_nl = dynamic_nl || '';
		// ask macro_parser to prepare this block
		var macro = woas.macro.parser($1);
		if (macro.reprocess) {
			// allow further parser processing
			return macro.text + (macro.block ? that.NL_MARKER : '') +
				dynamic_nl;
		}
		if (!macro.defn && snippets.length) {
			// text could have nowiki text in it so retrieve now
			// (don't want snippet references stored in snippets).
			// can't use undry because of name difference; FIX?
			macro.text = macro.text.replace(that.reBaseSnippet,
				function (str, $1) {
					return snippets[parseInt($1)];
				})
		}
		if (macro.block) {
			// definitions and block macros
			return that.place_holder_dnl(snippets, macro.text, dynamic_nl)
		}
		return that.place_holder(snippets, macro.text) + dynamic_nl;
	});
},

// 'inline' has no breaks at all between the markers.
// 'multiline' has first and last \n removed
parse_nowiki: function(P, snippets) {
	var that = this;
	P.body = P.body.replace(this.reNowiki, function (str, n1, nw, n2, dynamic_nl) {
		if (n1 || n2 || nw.indexOf("\n") !== -1) {
			nw = woas.parser._raw_preformatted("pre", nw, "woas_nowiki_multiline");
			return that.place_holder_dnl(snippets, nw, dynamic_nl);
		} else {
			nw = woas.parser._raw_preformatted("tt", nw, "woas_nowiki");
			return that.place_holder(snippets, nw) + (!dynamic_nl ? '' : dynamic_nl);
		}
	});
},

// new table parsing by FBNil
parse_tables_new: function (str, prop, p1) {
    var caption = '',
		colgroup = '',
		stk = [],
		cols = [],
		CC = [];
	// variables used by replace callback
	var i, C, CL;
    p1.replace(woas.parser.reReapTablesNewSub1, function (str, pp1, pp2) {
		switch (pp1) {
			case '-': // comment
				return;
			case '+':
				return (caption = caption || ('<'+'caption' + (stk.length > 0 ? ' style="caption-side:bottom">' : '>') + pp2 + '<'+'/caption>'));
			case '*':
				return (colgroup = pp2);
			case '$':
				return CC.push(pp2);
			case '|':
				pp2 = " |" + pp2;
			break;
			case ' ':
				if (pp2.match(/^\|/)) // fix empty first cell
					pp2 = "  " + pp2;
			break;
			default:
				// do not eat the first character if it's not a control character
				pp2 = pp1+pp2;
		}

        var cells = pp2.replace(woas.parser.reReapTablesNewSub2, "$1$2$3  ").
				replace(woas.parser.reReapTablesNewSub3, "$1 ").
				replace(woas.parser.reReapTablesNewSub4, "|| ").
				replace(woas.parser.reReapTablesNewSub5, " ||").split(" || "),
			row = [],
			stag = "",
			cs = 0;
        for (i = cells.length - 1; i >= 0; --i) {
            C = cells[i].match(woas.parser.reReapTablesHead);
            if (i && !C[3] && !C[1] && !C[2]) {
                ++cs;
                continue;
            } else if (i == 0 && !C[3]) C[3] = "&nbsp;";
            CL = C[2] ? C[2].length : 0;
            stag = '<' + (CL == 1 ? 'th' : 'td') + (CL > 1 ? ' ' + CC[CL - 2] || '' : '') + (cs ? ' colspan=' + (++cs) : '') + (C[1] ? ' align=' + (C[4] ? 'center' : 'right') : '') + '>';
            cs = 0;
            row.unshift(stag + C[3] + (CL == 1 ? '<'+'/th>' : '<'+'/td>'));
        }
        stk.push(row.join(""));
    });
    return '<'+'table ' + ((prop.indexOf("class=")!==-1) ? '' : 'class="woas_text_area" ') + prop + '>' + caption + colgroup + '<'+'tr>' + stk.join('<'+'/tr><'+'tr>') + '<'+'/tr>' + '<'+'/table>' + woas.parser.NL_MARKER;
},

/* PVHL:
 * Removed separator as unneeded.
 * Rewrote to perform entire place_holder function here. Will be slightly slower
   but only optimize if truly needed. Rest of code is much simpler this way.
 * Existence of dnl needs to be checked for IE so parameter is technically optional.
 * Split function into place_holder_dnl and place_holder for simplicity/readability
 * place_holder_dnl marks a following newline for later removal if it exists
*/
place_holder: function (snippets, str) {
	snippets.push(str);
	return this.marker + (snippets.length - 1) + ';';
},

place_holder_dnl: function (snippets, str, dnl) {
	snippets.push(str);
	return this.marker + (snippets.length - 1) + ';' +
		(!dnl ? '' : this.NL_MARKER + dnl);
},

// NOTE: XHTML comments can now be contained in nowiki and macro blocks
//  no_macros used by macro.parse; optional
pre_parse: function(P, snippets, no_macros) {
	var that = this;
	// put away stuff contained in nowiki blocks {{{ }}}, macros, and XHTML-style comments
	this.parse_nowiki(P, snippets);
	if (!no_macros) { this.parse_macros(P, snippets); }
	P.body = P.body.replace(this.reComments, function (str, comment, dynamic_nl) {
		// don't skip anything -- remove all comments for future syntax needs
		return that.place_holder_dnl(snippets, str, dynamic_nl);
	});
},

render_error: function(str, symbol) {
	//	if (typeof symbol == "undefined")
	//		symbol = "infin";
	symbol = "&"+symbol+";";
	return "<"+"span style=\"color:red;font-weight:bold;\">"+symbol+" "+str+" "+symbol+"<"+"/span>";
},

// split one or more tags (NOTE: no trim applied)
split_tags: function(tlist) {
	if (tlist.indexOf(",")!==-1)
		return tlist.split(",");
	//DEPRECATED but still supported
	return tlist.split("|");
},

// parse passive syntax only
syntax_parse: function(P, snippets, tags, export_links, has_toc) {
	var that = this;

	// restore text lines (lines ending in '\' are joined)
	P.body = P.body.replace(/\\\n/g, "")

	// put HTML tags and tag sequences away (along with attributes)
	.replace(this.reHtml, function(str, ws, tags, last, dnl) {
		// stop certain html block tags from having a br tag appended when at line end
		if (that.reBlkHtml.test(last))
			return ws + that.place_holder_dnl(snippets, tags, dnl);
		return ws + that.place_holder(snippets, tags) + (!dnl ? '' : dnl);
	})

	// render links e.g. [[target]] & [[target|label]]
	.replace(this.reWikiLink, function(str, target, label) {
		if (target)
			return that._render_wiki_link(target, label, snippets, tags, export_links);
		return str; // not a valid link
	})

	// remove URL style text ('*://*') to avoid parsing problems.
	.replace(this.reAutoLinks, function(str, prot) {
		// only return a link if autolinks on and a target exists
		return that.place_holder(snippets,
			woas.config.auto_links && prot && (prot.length + 3 !== str.length)
			? '<'+'a class="woas_world_link" href="'+str+
				'" target="_blank">'+str+'<'+'/a>'
			: str);
	})

	// italics/underline/bold all operate on a single line now; otherwise
	// they act as they did in 0.12.0 unless otherwise noted.

	// italics (needs to be done before code that adds html; this should be fixed
	// by changing how block level syntax is parsed). Italics can't start after a
	// colon, presumably to stop 'c:/my/path' from disappearing. Will fix in new.
	.replace(/(^|_|[^\w:])\/(.+?)\//mg, "$1<"+"em>$2<"+"/em>")

	// underline (now works on a single line the same as bold/italics)
	.replace(/(^|[^\w])_(.+?)_/mg, "$1<"+
		"span style=\"text-decoration:underline;\">$2<"+"/span>")

	// ordered/unordered lists parsing (code by plumloco)
	.replace(this.reListReap, this.parse_lists)

	// tables-parsing pass (parse_tables & reReapTables are in legacy.js)
	.replace(woas.config.new_tables_syntax ? this.reReapTablesNew : this.reReapTables,
				woas.config.new_tables_syntax ? this.parse_tables_new : this.parse_tables
	)

	// bold (needs to be after lists & tables). 0.12.0 doesn't allow start
	// after / or \; this code does as can't see need, esp. with URLs protected
	.replace(/(^|[^\w])\*(.+?)\*/mg, "$1<"+"strong>$2<"+"/strong>")

	// horizontal rulers: multiline RE used; adding NL_MARKER will remove the \n following.
	.replace(this.reRuler, this._HR + this.NL_MARKER);

	// other custom syntax should go into this callback
	this.extend_syntax(P);

	// headings - only h1~h6 are parsed;
	P.body = P.body.replace(this.reHeading, function(str, depth, heading) {
		//that.heading_replace(depth, heading, snippets);
		if (!heading) { return str; } // needed?
		var anchor, toc_entry, len = depth.length;
		// remove any markers and html
		toc_entry = heading.replace(that.reBaseSnippet, function (str, $1) {
				return snippets[parseInt($1)];
			})
			.replace(/(<\/?\w+[^>]*>)+/g, '');
		anchor = that.heading_anchor(toc_entry);
		if (that.has_toc) { // [level, anchor, straight heading text, ...]
			that.toc.push(len);
			that.toc.push(anchor);
			that.toc.push(toc_entry);
		}
		return "<"+"h"+len+" class=\"woas_heading\" id=\"" + anchor +
			"\">" + heading + "<"+"/h"+len+">" + woas.parser.NL_MARKER;
	});

	// replace [[Special::TOC]]
	if (has_toc) {
		P.body = P.body.replace(this.marker+"TOC", function() {
			return that.toc_render(export_links);
		});
	}

	// clear dynamic newlines
	P.body = P.body.replace(this.reNL_MARKER, "")

	// cleanup \n after certain block tags (set by reNewlineAfter)
	.replace(this.reNewlineAfter, "$1")

	// cleanup \n before certain block tags (set by reNewlineBefore)
	.replace(this.reNewlineBefore, "$1")

	// convert newlines to br tags
	.replace(/\n/g, "<"+"br />");

	// put back snippets removed by place_holder
	this.undry(P, snippets);
	snippets = null;
},

// override to generate a different style of TOC
toc_body: '<'+'div id="woas_toc"><' +
	'div id="woas_toc_title"><'+'a onclick="d$.toggle(\'woas_toc_content\')"' +
	'>%s<'+'/a><'+'/div><'+'div id="woas_toc_content">%s<'+'/div><'+'/div>',
toc_body_exp: '<'+'div id="woas_toc"><'+'div id="woas_toc_title">%s<' +
	'/div><'+'div id="woas_toc_content">%s<'+'/div><'+'/div>',
toc_line: '<'+'div class="woas_toc_h%s"><' +
	'a class="woas_link" onclick="woas.go_to(\'#%s\')">%s<'+'/a><'+'/div>',
toc_line_exp: '<'+'div class="woas_toc_h%s"><' +
	'a class="woas_link" href="#%s">%s<'+'/a><'+'/div>',
// to allow overriding of TOC line rendering
toc_line_render: function(level, count, anchor, heading) {
	// the count array could be used for section numbering; e.g. 1.1.2
	// for current count just use count[level]
	return this.toc_line.sprintf(level, anchor, heading);
},
// PVHL: added in case user wants different TOC generated for exported pages
toc_line_render_exp: function(level, count, anchor, heading) {
	// see notes for toc_line_render
	return this.toc_line_exp.sprintf(level, anchor, heading);
},
// replace the TOC placeholder with the real TOC
// This function should not need to be overwritten; toc_line_render, toc_line,
// & toc_body (and related export versions) should be sufficient to generate
// any desired TOC.
toc_render: function(export_links) {
	// this.toc: [level, anchor, heading text, level, anchor, ...]
	var i, il, j, tmp = [], count = [], level,
		body = export_links ? this.toc_body_exp: this.toc_body,
		line_fn = export_links ? this.toc_line_render_exp : this.toc_line_render;
	for (i = 0, il = this.toc.length; i < il;) {
		level = this.toc[i++];
		count[level] = count[level] ? count[level] + 1 : 1;
		for (j = level + 1; j < 7; ++j) {
			count[j] = 0;
		}
		// toc_line_render(level, count, anchor, heading)
		tmp.push(line_fn.call(this, level, count, this.toc[i++], this.toc[i++]));
	}
	this.toc = [];
	return body.sprintf(woas.i18n.TOC, tmp.join(''));
},

//API1.0
//TODO: offer transclusion parameters argument
transclude: function(title, snippets, export_links, img_gallery) {
	this._snippets = snippets;
	this._export_links = !!export_links;
	var rv = this._transclude("[[Include::"+title+"]]", title, img_gallery);
	this._export_links = this._snippets = null;
	return rv;
},

transclude_syntax: function(P, snippets, export_links) {
	var trans_level = 0, that = this, found;
	this._snippets = snippets;
	this._export_links = export_links ? true : false;
	do {
		found = false;
		P.body = P.body.replace(this.reTransclusion, function(str, $1) {
			found = true;
			return that._transclude(str, $1);
		});
		// keep transcluding when a transclusion was made and when transcluding depth is not excessive
	} while (found && ++trans_level < this._MAX_TRANSCLUSION_RECURSE);
	if (trans_level === this._MAX_TRANSCLUSION_RECURSE) { // parse remaining inclusions as normal text
		P.body = P.body.replace(this.reTransclusion, function (str, $1) {
			return that.place_holder(snippets, that.render_error(str, 'infin'));
		});
	}
	this._snippets = this._export_links = null;
},

// return all the snippets that were pushed to snippets array
undry: function(NP, snippets) {
	if (!snippets.length) return;
	NP.body = NP.body.replace(this.reBaseSnippet, function (str, $1) {
		return snippets[parseInt($1)];
	});
}

}; // end of parser module

// initialize here because IE would fail otherwise
woas.parser._init();
delete woas.parser._init;

/*** src/special.js ***/
// returns link exclusive of Include:: and any section or alternate text
var reAllWikiLinks = /\[\[(?:Include\:\:)?([^\|\]\#]+)(?:[^\]]*)?\]\]/g;

woas.special_encrypted_pages = function(locked) {
	var pg = [];
	for(var i=0,l=pages.length;i < l;i++) {
		if (this.is_reserved(page_titles[i]))
			continue;
		if (locked == this.is__encrypted(i))
			pg.push(page_titles[i]);
	}
	if (!pg.length)
		return "/No locked pages/";
	else
		return this._join_list(pg);
};

// PVHL: original algorithm was O(n*n) - this one is O(n).
// found contains every non-reserved page
// links contains every wiki link found in the page source
// ns contains every namespace found for page titles
woas.special_orphaned_pages = function() {
	var found = {}, links = {}, ns = {}, lnks, lnk, pg = [],
		i, il, t, tmp;
	// find all titles and namespaces in titles
	for (i = 0, il = page_titles.length; i < il; i++) {
		t = page_titles[i]; // to simplify reading
		if (!this.is_reserved(t)) {
			found[t] = true;
			if (!this.is_menu(t)) {
				tmp = this.get_namespace(t);
				if (tmp) {
					ns[tmp] = true;
				}
			}
		}
	}
	// find all links in pages
	for (i = 0, il = page_titles.length; i < il; i++) {
		t = page_titles[i]; // to simplify reading
		if (found[t] && (tmp = this.get_src_page(i))) {
			while((lnks = reAllWikiLinks.exec(tmp)) !== null) {
				lnk = this.title_unalias(this.trim(lnks[1]));
				if (lnk !== t && found[lnk]) {
					// don't care what kind of link it is
					links[lnk] = true;
				}
			}
		}
	}
	// check pages are linked
	for (t in found) {
		if (found.hasOwnProperty(t)) {
			if (this.is_menu(t)) {
				// check if the menu namespace has a page
				tmp = this.get_namespace(t);
				if (t === "::Menu" || tmp && ns[tmp]) {
					continue;
				}
			} else {
				// check if title has been found in pages
				if (links[t]) {
					continue;
				}
			}
			pg.push(t);
		}
	}
	if (!pg.length)
		return "/No orphaned pages/";
	else
		return this._join_list(pg);
};

woas.special_backlinks = function() {
	var pg = [], pg_title, tmp;
	if (this.parser.render_title === null)
		pg_title = current;
	else {
		pg_title = this.parser.render_title;
		this.parser.render_title = null;
	}
	var reg = new RegExp("\\[\\["+RegExp.escape(pg_title)+"(\\||\\]\\])", "gi");
	for(var j=0,l=pages.length; j < l; j++) {
		if (this.is_reserved(page_titles[j]))
			continue;
		// search for pages that link to it
		tmp = this.get_src_page(j);
		// encrypted w/o key
		if (tmp===null)
			continue;
		if (tmp.match(reg))
			pg.push( page_titles[j] );
	}
	if(pg.length === 0)
		return "/No user page links to [["+pg_title+"]]/";
	else
		return "== Links to [["+pg_title+"]]\n"+this._join_list(pg);
};

woas._reLastSearch = null;	// search highlighting regex

woas._nearby_chars = 200;		// amount of nearby characters to display

// cached search results
woas._cached_title_search = [];
woas._cached_body_search = [];
// last string searched
woas._last_search = null;

// create an index of searched pages (by miz & legolas558)
woas._cache_search = function( str ) {
	var count = 0, tmp,
		// matches the search string and nearby text
		reg = new RegExp( ".{0,"+this._nearby_chars+"}" + RegExp.escape(this.trim(str)).
					replace(/\s+/g, "(.|\n)*?") + ".{0,"+this._nearby_chars+"}", "gi" );

	this._reLastSearch = new RegExp("("+RegExp.escape(str)+")", "gi");
	
	this._last_search = str;

	for(var i=0,l=pages.length; i < l; i++) {

		//TODO: implement searching in help pages

		if (this.is_reserved(page_titles[i]) && !this.tweak.edit_override)
			continue;

		// this could be modified for wiki searching issues
		tmp = this.get_src_page(i, true);
		if (tmp===null)
			continue;
	
		// look for string in title
		if(page_titles[i].match(reg)) {
			this._cached_title_search.push(page_titles[i]);
		}

		// look for string in body
		res_body = tmp.match(reg);
		if (res_body !== null)
			this._cached_body_search.push( { title: page_titles[i],	 matches: res_body} );
	}
};

woas.special_tagged = function(filter_string) {
	var	reFindTags = /\[\[Tags?::([^\]]+)\]\]/g,
		pg = [], pgi = [], folds = {}, tags, tag, tagns, alltags,
		src, i, il, j, jl, k, kl, tmp, filtering;
	// filtering setup
	if (typeof filter_string != "undefined") {
		filtering = woas.tagging._prepare_filter(filter_string);
	} else {
		filtering = false;
	}
	// scan all pages
	for(i = 0, il = pages.length; i < il; ++i) {
		if (this.is_reserved(page_titles[i]))
			continue;
		src = this.get_src_page(i);
		// encrypted w/o key
		if (src === null)
			continue;
		src.replace(reFindTags, function (str, $1) {
				// get the tags and index the page under each tag
				tmp = woas.parser.split_tags($1);
				alltags = [];
				for(j = 0, jl = tmp.length; j < jl; ++j) {
					tag = woas.trim(tmp[j]);
					// skip invalid tags
					if (!tag.length) {
						woas.log("WARNING: check your tag separators");
						continue;
					}
					// call the filtering callback, if necessary
					if (filtering) {
						// skip this page from listing in case of negative filter result
						if (!woas.tagging._filter_not_cb(tag))
							break;
					}
					alltags.push(tag);
				}
				tmp = null;
				// check that page has at least one of the positive tags
				if (filtering && !woas.tagging._filter_ok_cb(alltags))
					return;
				// add page to proper leaves
				for (j = 0, jl = alltags.length; j < jl; ++j) {
					tag = alltags[j];
					if (filtering && !woas.tagging._filter_ok_tag(tag)) {
						continue;
					}
					// we have a valid tag, check if it is already indexed
					if (!folds[tag]) {
						folds[tag] = [page_titles[i]];
					} else {
						folds[tag].push(page_titles[i]);
					}
					// build the flat list with tags listed
					if (!pgi[i]) {
						pgi[i] = true;
						tags = alltags.slice(0).sort();
						tmp = "[["+page_titles[i]+"]]\n** [[Tagged::"+tags.join()+"|Tags]]: ";
						for (k = 0, kl = tags.length; k < kl;) {
							tmp += " [[Tagged::"+tags[k]+"|"+tags[k]+"]]"+(++k === kl ? "" : ", ");
						}
						pg.push(tmp);
					}
				}
			});
	} // scan pages loop
	pgi = null;
	if (filtering) {
		woas.tagging._finish();
	}
	if (pg.length) {
		// parse tree with sorting
		return woas.ns_listing("", pg, folds);
	} else {
		return "/No tagged pages/";
	}
};

// @module 'tagging'
woas.tagging = {
	tags_ok: null,
	tags_not: null,

	_finish: function() {
		this.tags_ok = this.tags_not = null;
	},

	_prepare_filter: function(filter_string) {
		var i,l, pg = [];
		// allow tags filtering/searching
		var tags = woas.parser.split_tags(filter_string);
		// reset filter
		this.tags_ok = [];
		this.tags_not = [];

		// parse filter
		for(i=0,l=tags.length;i < l;++i) {
			// skip empty tags
			var tag = woas.trim(tags[i]);
			if (!tags[i].length)
				continue;
			// add a negation tag
			if (tags[i].charAt(0) === '!')
				this.tags_not.push( tags[i].substr(1) );
			else // normal match tag
				this.tags_ok.push(tags[i]);
		}
		tags = null;
		return (this.tags_ok.length + this.tags_not.length > 0);
	},

	// return true if all OK tags are present
	_filter_ok_cb: function(tags) {
		var ok = 0;
		if (this.tags_ok.length) {
			for(var i=0,il=tags.length;i < il;++i) {
				if (this.tags_ok.indexOf(tags[i]) !== -1)
					++ok
			}
		}
		return (ok === this.tags_ok.length);
	},

	// check single tag is in OK filter
	_filter_ok_tag: function(tag) {
		return this.tags_ok.indexOf(tag) !== -1;
	},

	_filter_not_cb: function(tag) {
		// filter if "NOT" tag is present
		// we are applying this filter only to tagged pages
		// so a page without tags at all does not fit into this filtering
		if (this.tags_not.length) {
			if (this.tags_not.indexOf(tag) !== -1)
				return false;
		}
		// no failure, this page passes
		return true;
	}
		
};

var reHasTags = /\[\[Tags?::[^\]]+\]\]/;
woas.special_untagged = function() {
	var tmp;
	var pg = [];
	for(var i=0,l=pages.length; i < l; i++) {
		if (this.is_reserved(page_titles[i]))
			continue;
		tmp = this.get_src_page(i);
		if (tmp === null)
			continue;
		if (!tmp.match(reHasTags))
			pg.push(page_titles[i]);
	}
	if (!pg.length)
		return '/No untagged pages/';
	return this._join_list(pg);
};

// Returns a index of all pages
woas.special_all_pages = function() {
	var pg = [];
	for(var i=0, l=page_titles.length; i < l; i++) {
		if (!this.is_reserved(page_titles[i]))
			pg.push( page_titles[i] );
	}
	return this._join_list(pg);
};

// Returns a index of all dead pages
woas.special_dead_pages = function() {
	var dead_pages = [], from_pages = [], pg = [],
		reIgnore = /^(\w+:\/\/|Tags?::|Tagged::|mailto:|Special::TOC)/i,
		tmp, page_done, i, j, l, p, sectref;
	for(j=0,l=pages.length;j < l;j++) {
		if (this.is_reserved(page_titles[j]) && !this.tweak.edit_override)
			continue;
		tmp = this.get_src_page(j);
		if (tmp===null)
			continue;
		page_done = false;
		tmp.replace(reAllWikiLinks,
			function (str, $1, $2, $3) {
				p = woas.trim(woas.title_unalias($1));
				// ignore external and reserved links
				if (reIgnore.test(p)) {
					return;
				}
				if ((p.substr(0, 9) === "Special::") &&
					(woas.shortcuts.indexOf(p.substr(9)) !== -1))
					return;
				if (!woas.page_exists(p) && (p!==page_titles[j])) {
					// true when page has been scanned for referrals
					page_done = false;
					// check that this not-existing page is already in the deads page list
					for(i=0;i < dead_pages.length;i++) {
						// current page contains a link to an already indexed dead page,
						// save the reference
						if (dead_pages[i]===p) {
							// add only if not already there
							if (from_pages[i].indexOf(page_titles[j]) === -1)
								from_pages[i].push(page_titles[j]);
							page_done = true;
							break;
						}
					}
					// we have just found a dead page
					if (!page_done) {
						dead_pages.push(p);
						from_pages.push(new Array(page_titles[j]));
						page_done = true;
					}
				}
	        }
		);
	}

	// format the dead pages
	for(var i=0;i < dead_pages.length;i++) {
		j = from_pages[i];
		l = j.length;
		pg.push("[["+dead_pages[i]+"]] from " + (l ? "[[" : "") +
			j.sort().join("]], [[") + (l ? "]]" : ""));
	}

	woas.pager.bucket.items = dead_pages.slice(0);
	if (!pg.length)
		return '/No dead pages/';
	return this._simple_join_list(pg, true);
};

// used in Special::Options
function bool2chk(b) {
	if (b) return "checked";
	return "";
}

//Special::Recent Changes shows a sorted list of pages by modified timestamp
woas.special_recent_changes = function() {
	if (!this.config.store_mts) {
		return "/Last modified timestamp storage is disabled in [[Special::Options]]./";
	}
	// build an array of (key := page_index, val := last_modified_timestamp) couples
	var l=page_titles.length, hm = [], i;
	for(i=0;i < l;++i) {
		// skip pages with the 'magic' zero timestamp
		if (page_mts[i] === 0)
			continue;
		// skip reserved pages which are not editable
		if (!this.edit_allowed_reserved(page_titles[i]) && this.is_reserved(page_titles[i]))
			continue;
		hm.push([i,page_mts[i]]);
	}
	// sort the array
	hm.sort(function(a,b) { return (b[1]-a[1]); });
	// display results
	var pg=[];
	for(i=0,l=hm.length;i < l;++i) {
		pg.push("* [[" + page_titles[hm[i][0]] + "]]&nbsp; <"+"span style=\"font-size: smaller;\">"+this.last_modified(hm[i][1],true)+"<"+"/span>");
	}
	if (!pg.length)
		return "/No recently modified pages/";
	return this._simple_join_list(pg);
};

woas._simple_join_list = function(arr, sorted) {
	if (sorted) { arr = arr.sort(); }
	return arr.join("\n")+"\n";
};

// creates a tree from array then sorts and creates listing
woas._join_list = function(arr) {
	if (!arr.length) { return ""; }
	// copy the array to currently selected pages
	woas.pager.bucket.items = arr.slice(0);
	var root = "::", ns = {}, folds = {}, i, il, tmp;
	folds[root] = [];
	for (i = 0, il = arr.length; i < il; ++i) {
		tmp = this.get_namespace(arr[i]);
		if (tmp === "::") {
			tmp = "";
		}
		if (tmp && !folds[tmp]) {
			folds[tmp] = [arr[i]];
		} else {
			folds[tmp ? tmp : root].push(arr[i]);
		}
	}
	return this.ns_listing(root, arr, folds);
};

function _WoaS_list_expand_change(list, list_id, count) {
	var i, s;
	// store selected option in global config variable
	woas.config.folding_style = list.selectedIndex;
	switch (woas.config.folding_style) {
		case 1: // collapse all
			d$.show(list_id+"folds");
			d$.hide(list_id+"flat");
			for(i = 0; i < count; ++i) {
				d$.hide(list_id + i);
			}
		break;
		case 0: // flat list
			d$.hide(list_id+"folds");
			d$.show(list_id+"flat");
			break;
		case 2: // expand all
			d$.show(list_id+"folds");
			d$.hide(list_id+"flat");
			for(i = 0; i < count; ++i) {
				d$.show(list_id + i);
			}
		break;
	}
}

// PVHL: have removed non-functional list caching until it can be made to work
// (cache needs to be invalidated after edit/import, etc; should work off of history)
// listing is always sorted
// flat_arr must have content
woas.ns_listing = function(root, flat_arr, folds) {
	dsp = function(v){
		return v ? "display:block" : "display:none";
	};
	opt = function(str) {
		return "<"+"option "+(fs === opt_n++ ? "selected=\"selected\"" : "" ) +
			">"+str+"<"+"/option>\n";
	};

	var order = [], root_title = "/No Namespace/", fold_n = 0, opt_n = 0, s = "",
		list_id = "woas_"+_random_string(6)+"_", f, i, il, it, oi, ns, fs;
	flat_arr.sort();
	// sort folds content and folds
	// do not produce the header if listing is transcluded
	if (!woas.parser._transcluding) {
		for (f in folds) {
			if (folds.hasOwnProperty(f)) {
				folds[f].sort();
				if (f !== root) {
					order.push(f);
				}
			}
		}
		f = false;
		// or if it has no subnamespaces
		if (order.length) {
			order.sort();
			f = true;
		}
		if (root && folds[root].length) {
			order.splice(0, 0, root);
		}
	};
	if (f) {
		// create list control
		fs = woas.config.folding_style;
		s = "<"+"div class=\"woas_list_options\">List view:&nbsp;<" +
			"select onchange=\"_WoaS_list_expand_change(this,'"+list_id+"',[" +
			order.length+"])\">\n" + opt("Pages") +
			opt(root ? "Namespace, collapsed" : "Tags, collapsed") +
			opt(root ? "Namespace, expanded" : "Tags, expanded") +
			"<"+"/select>\n<"+"/div>\n<"+"div style=\""+dsp(fs !== 0) +
			"\" id=\""+list_id+"folds\">\n"+(root ? "" : "==Tags\n");
		// fill the folding divs
		for (i = 0, il = order.length; i < il; ++i) {
			fold_id = list_id + fold_n++;
			oi = order[i];
			if (root) {
				ns = i === 0 && oi === root ? root_title : "[["+oi+"]]";
			} else {
				ns = "[[Tagged::"+oi+"|"+oi+"]]";
			}
			it = folds[oi].length;
			s += "<"+"div"+" class=\"woas_list_heading\">"+ns+"&nbsp;&nbsp;<" +
				"a class=\"woas_list_link\" title=\"Toggle page display\" onclick=\"d$.toggle('" +
				fold_id+"')\">"+it+" page"+(it > 1 ? "s" : "")+"<"+"/a>\n<"+"/div>\n" +
				"<"+"div style=\""+dsp(fs === 2)+"\" id=\""+fold_id+"\">\n<" + 
				"div class=\"woas_list\">\n[["+folds[oi].join("]]\n[[")+"]]<"+"/div><"+"/div>\n";
		}
		// finish up
		s += "<"+"/div>\n"+
			"<"+"div style=\""+dsp(fs === 0)+
			"\" id=\""+list_id+"flat\">\n";
	}
	// generate the flat list
	s += root ? "* [["+flat_arr.join("]]\n* [[")+"]]\n" : "==Pages\n* "+flat_arr.join("\n* ")+"\n";
	if (f) {
		s += "<"+"/div>";
	}
	return s;
};

// PVHL: have cleaned up and added some HTML/CSS that should help
//   make things work in every browser, even IE6
//   (IE6 only has a:hover and doesn't like multi-class selectors)
woas._special_image_gallery = function(ns) {
	var snippets = [], div = [], i, l, cnt, t, cls = 'woas_img_list',
		plus = '', p = {},
		// class, title
		line1 = '<'+'a class="%s" onclick="woas.go_to(\'%s\')">',
		// title
		line2 = '<'+'div class="'+cls+'">%s<'+'/div><'+'/a>';
	for (i = 0, l = page_titles.length, cnt = 0; i < l; ++i) {
		if (page_titles[i].indexOf(ns) === 0) {
			div[cnt++] = page_titles[i];
		}
	}
	l = div.length;
	// first image
	if (l) {
		plus = cls + (l === 1 ? '_single' : '_first');
		t = div[0];
		div[0] = line1.sprintf(plus, t) +
			this.parser.transclude(t, snippets, false, true) +
			line2.sprintf(t);
	}
	--l;
	// last image (if more than one)
	if (l > 0) {
		plus = cls + '_last';
		t = div[l];
		div[l] = line1.sprintf(plus, t) +
			this.parser.transclude(t, snippets, false, true) +
			line2.sprintf(t);
	}
	// everything in between
	for (i = 1; i < l; ++i) {
		t = div[i];
		div[i] = line1.sprintf(cls, t) +
			this.parser.transclude(t, snippets, false, true) +
			line2.sprintf(t);
	}
	if (div.length) {
		p.body = '= Pages in '+ns+' namespace\n' + div.join('');
	} else {
		p.body = this.i18n.EMPTY_NS.sprintf(ns);
	}
	this.parser.syntax_parse(p, snippets);
	snippets = div = null;
	return p.body;
};

/*** src/core.js ***/
// core modules

// some tweak settings NOT to be touched - warranty void otherwise
woas.tweak = {
	// DANGER: might cause WoaS corruption!
	edit_override: false,
	// perform integrity test of browser features
	integrity_test: false
};

woas.cmd_duplicate_page = function() {
	var pname = this._new_page(this.i18n.DUPLICATE_PAGE, true, current+" (duplicate)");
	if (pname === null)
		return;
	var pi = this.page_index(current);
	var dpi = this.page_index(pname);
	// duplicate the page
	if (this.is__encrypted(pi)) // encrypted pages are arrays
		pages[dpi] = pages[pi].slice(0);
	else // string copy is OK
		pages[dpi] = pages[pi]; // .slice ?
	page_attrs[dpi] = page_attrs[pi];	
	// go to new page
	this.go_to(pname);
	// commit changes
	this.commit([dpi]);
};

woas.cmd_new_page = function() {
	this._new_page(this.i18n.INSERT_NEW, false, '');
};

// used to create a new page in the wiki
woas._new_page = function(msg, fill_mode, title) {
	title = this._prompt_title(msg, title, false);
	if (title === null)
		return null;
	return this._new_page_direct(title, fill_mode);
};

// will return a valid title for an about-to-be-created page
// PVHL: if called with plugin = true will check plugin title.
// EXISTING BUG: tweak.edit_override could create a bad plug-in here (@), but this
// fixes issue of not allowing plug-in with same name as an existing page.
// Workaround: don't create plugins with "new page" in edit_override mode!
woas._prompt_title = function(msg, title, plugin) {
	// disallow editing when wiki is set to read-only
	if (!this.config.permit_edits) {
		this.alert(this.i18n.READ_ONLY);
		return null;
	}
	var _title;
	while (true) {
		title = prompt(msg, title);
		if (title === null)
			return null;
		title = this.trim(title);
		if (this.valid_title(title)) {
			if (plugin) {
				_title = title;
				title =  "WoaS::Plugins::" + title;
			}
			if (this.page_index(title) === -1) {
				return plugin ? _title : title;
			} else {
				// page exists: warn and try again
				this.alert(this.i18n.PAGE_EXISTS.sprintf(title));
				if (plugin) title = _title;
			}
		}
	}
};

woas._new_page_direct = function(title, fill_mode) {
	// properly split page title in (namespace, title) -> (ns, cr)
	var ns = this.get_namespace(title, true), cr;
	if (ns.length) {
		cr = title.substr(ns.length);
		ns = ns.substr(0, ns.length-2);
	} else cr = title;

	// check if page deserves creation
	if ((ns==="File") || (ns==="Image")) {
		this.go_to(title);
		return title;
	}
	// create and edit the new page
	var ct;
	if (cr !== "Menu")
		ct = "= "+cr+"\n";
	else
		ct = "\n";
	this._create_page_direct(ns, cr, fill_mode, ct);

	if (cr !== 'Menu') {
		var menu = this.get_text("::Menu"),
			test = new RegExp("\\[\\["+title+"\\s*[\\|\\]]");
		// ask if menu link wanted (if option allows) if one doesn't already exist
		if (!menu.match(test) && (this.config.menu_link === 1 ||
				(!this.config.menu_link && confirm(this.i18n.ASK_MENU_LINK)))) {
			// try to put the menu link in a good position
			p = menu.indexOf("\n\n");
			if (p === -1)
				menu += "\n[["+title+"]]";
			else
				menu = menu.substring(0,p+2)+"[["+title+"]]\n"+menu.substring(p+2);
			this.set__text(this.page_index("::Menu"), menu);
		}
	}
	return title;
};

// used to eventually remove the new-to-be page when cancel is pressed
woas._ghost_page = false;

woas._create_page_direct = function(ns, cr, fill_mode, default_ct) {
	// actual page creation
	pages.push(default_ct);
	if (ns.length)
		cr = ns+"::"+cr;
	page_attrs.push(0);
	page_titles.push(cr);
	// set modified timestamp
	page_mts.push(this.config.store_mts ? Math.round(new Date().getTime()/1000) : 0);
//	this.log("Page "+cr+" added to internal array");	// log:1
	if (!fill_mode) {
		// DO NOT set 'current = cr' here!!!
		// enable ghost mode when creating a new-to-be page
		this._ghost_page = true;
		this.log("Ghost page enabled"); //log:1
		// proceed with a normal wiki source page
		this.edit_page(cr);
	}
};

woas.cmd_erase_wiki = function(page) {
	if (this.erase_wiki()) {
		if (!this.full_commit()) {
			this.alert(this.i18n.FAILED_ERASE);
			// reload page because all data is lost - works even in IE6
			window.location = window.location;
		}
		// PVHL: successful erase; if called from an Import page will go back there
		this.set_current(page ? page : this.config.main_page, true);
	}
	return null;
};

// pages which shall never be modified
woas.static_pages = [
	"Special::About", "Special::Advanced", "Special::Options",
	"Special::Import", "Special::Lock","Special::Search", "Special::Embed",
	"Special::Export", "Special::License", "Special::ExportWSIF",
	"Special::ImportWSIF"
];

woas.static_pages2 = [
	"WoaS::Plugins", "WoaS::CSS::Boot", "WoaS::CSS::Core", "WoaS::Help",
	"WoaS::ImportSettings", "WoaS::Template::Search", "WoaS::Template::Info"
];

woas.static_pages = woas.static_pages.concat(woas.static_pages2);
						
woas.erase_wiki = function() {
	if (!this.config.permit_edits) {
		this.alert(this.i18n.READ_ONLY);
		return false;
	}
	if (!confirm(this.i18n.CONFIRM_DELETE_ALL1) ||
		!confirm(this.i18n.CONFIRM_DELETE_ALL2)) {
		return false;
	}
	var _titles, _pages, i, il, pt, pi;
	this.progress_init("Erasing...");
	_titles = [this.config.main_page, "::Menu", "WoaS::Aliases",
			"WoaS::Hotkeys", "WoaS::CSS::Custom"];
	_pages = ["A blank sheet is a catalyst for ideas",
		"[["+this.config.main_page+"]]\n[[Special::Options|Options]]\n\n"+
		"* [[Special::All Pages|All Pages]]\n* [[Special::Go to|Go to...]]\n"+
		"* [[Special::Recent Changes|Recent Changes]]\n\n"+
		"* [[Special::Backlinks|Backlinks]]\n"+
		"* [[Special::New Page|New Page]]\n"+
		"* [[Special::Duplicate Page|Duplicate Page]]\n"+
		"* [[Special::Delete Page|Delete Page]]\n\n\n"+
		"[[Include::WoaS::Template::Search]]\n",
		"Lines that do not start with '$' are ignored\n\n$JS  Javascript",
		this.hotkey._cache_default(),
		"/* Your CSS customization goes here */"];
	// add all system pages
	for (i = 0, il = page_titles.length; i < il; ++i) {
		pt = page_titles[i];
		if (pt.indexOf("WoaS::Help") === 0 ||
				pt.indexOf("Special::") === 0 ||
				this.static_pages2.indexOf(pt) !== -1) {
			pi = this.page_index(pt);
			if (pi === -1) {
				this.alert(this.i18n.STATIC_NOT_FOUND.sprintf(pt));
				continue;
			}
			_pages.push(pages[pi]);
			if (!_pages[_pages.length - 1]) {
				_pages.pop();
				continue;
			}
			_titles.push(pt);
		}
	}
	// PVHL: This is where save could be done with temporary arrays.
	// This whole function could be done in save though - save instead
	// of erase, with save only saving core pages. Simple flag.
	pages = _pages;
	page_titles = _titles;
	// attributes and last modified timestamps for new pages
	// zero is the magic timestamp
	page_attrs = [];
	page_mts = [];
	for (i = 0, il = _pages.length; i < il; ++i) {
		page_attrs.push(0);
		page_mts.push(0);
	}
	current = this.config.main_page;
// PVHL: FIX this needs to be moved at some point
	this.ui.refresh_menu();
	this.history.clear();
	// reload all extensions
	this._load_aliases(this.get_text("WoaS::Aliases"));
	this.hotkey.load(this.get_text("WoaS::Hotkeys"));
	// remove all plugins
	this.plugins.clear();
	this.plugins.load();
	this.progress_finish();
	return true;
};

woas.cmd_main_page = function() {
	this.go_to(this.config.main_page);
	return null;
};

// used to edit many special pages
woas.cmd_edit_special = function(cr) {
	if (!this.config.permit_edits && !this.tweak.edit_override) {
		this.alert(this.i18n.READ_ONLY);
	} else {
		// get source text (ASCII/UTF-8)
		var tmp = this.get_text(cr);
		if (tmp !== null) {
			// setup the wiki editor textbox
			this.current_editing(cr, this.config.permit_edits || this._server_mode, tmp);
		}
	}
	return null;
};

woas.cmd_go_to = function() {
	// don't go anywhere if editing
	if (this.ui.edit_mode)
		return;
	var pname;
	do {
		pname = prompt(this.i18n.GO_TO_PAGE, current);
		if ((pname !== null) && pname.length)
			if (this.go_to(pname))
				return;
	} while (pname !== null);
};

woas.cmd_delete = function() {
	// disallow editing when wiki is set to read-only
	if (!this.config.permit_edits) {
		this.alert(this.i18n.READ_ONLY);
	} else {
		var pname, pi;
		while ((pname = prompt(this.i18n.DELETE_PAGE_PROMPT, current)) !== null) {
			if (!pname.length)
				continue;
			pi = this.page_index(pname);
			if (pi === -1) {
				this.alert(this.i18n.PAGE_NOT_EXISTS.sprintf(pname));
				continue;
			} else if (this.is_reserved(pname)) {
				this.alert(this.i18n.ERR_RESERVED_NS.sprintf(this.get_namespace(pname, true)));
				continue;
			} else if (confirm(this.i18n.CONFIRM_DELETE.sprintf(pname))) {
				this.plugins.delete_check(pname);
				this.delete_page_i(pi);
				return true;
			}
		}
	}
	return false;
};

// javascript shortcuts for special pages
woas.shortcuts = ["New Page", "Duplicate Page", "All Pages", "Orphaned Pages", "Backlinks",
					"Dead Pages", "Erase Wiki", "Main Page", "Go to", "Delete Page", "Recent Changes"];
woas.shortcuts_js = ["cmd_new_page", "cmd_duplicate_page", "special_all_pages", "special_orphaned_pages", "special_backlinks",
					"special_dead_pages", "cmd_erase_wiki",	"cmd_main_page", "cmd_go_to", "cmd_delete",	"special_recent_changes"];

// PVHL: moved unexportable lists to export.js

// return raw javascript tag to be included in XHTML page
woas.raw_js = function(code) {
	return "<"+"script type=\"text/javascript\">\n"+code+"\n<"+"/s"+"cript>";
};

//API1.0: delete a page given title (without aliases)
woas.delete_page = function(title) {
	var pi = page_titles.indexOf(title);
	//DEBUG line
	if (pi === -1) {
		this.crash("Requesting deletion of unexisting page!");
		return false;
	}
	return this.delete_page_i(pi);
};

//API1.0: delete a page given absolute page index
//API1.0: @protected
woas.delete_page_i = function(i) {
	var il, old_title = page_titles[i];
//	this.log("NOTICE: deleted page "+old_title);	// log:0
	// remove the elements
	page_titles.splice(i,1);
	pages.splice(i,1);
	page_attrs.splice(i,1);
	page_mts.splice(i,1);
	// if we were looking at the deleted page
	if (current === old_title) {
		// go to an existing page
		this.set_current(this.history.previous(), true);
	} else {
		// always refresh the menu because it could contain the deleted page link
		// done automatically above
		this.ui.refresh_menu();
	}
	// remove page from history
	this.history.clear(old_title);
	//TODO: send proper save notification
	return this.commit_delete([i]);
};

// PVHL: Can't make changes to API I would like to without reworking a lot of
//   the code. The changes I have made attempt to fix current history issues.
 
woas.history = (function(){ // woas.history closure
	// commandeer the old backstack (breaks privacy; good enough for now)
	// much easier if it was one stack, but this way for historical reasons
	var backstack = window.backstack,
		forstack = [], // forward history stack, discarded when saving
		going_back = true,	// true if back called and for initial page load
		going_forward = false; // true if forward called
	
	// push a page into history
	function store(page) {
		if (/^(Lock|Javascript)::/.test(current)) {
			return;
		}
		if (backstack.length > woas.history.MAX_BROWSE_HISTORY)
			backstack = backstack.slice(1);
		backstack.push(page);
	}
	
	// the public API
	return {

	MAX_BROWSE_HISTORY: 6, // public for overriding
	
	has_forstack: function() {
		return (forstack.length > 0);
	},
	
	has_backstack: function() {
		return (backstack.length > 0);
	},
	
	previous: function() {
		// go back or to main page, do not save history
		if (backstack.length > 0) {
			return backstack.pop();
		} else
			return woas.config.main_page;
	},
	
	back: function() {
		if (backstack.length > 0) {
			if (!/^(Lock|Javascript)::/.test(current)) {
				forstack.push(current);
			}
			var title = backstack.pop();
			if (title)
				going_back = true;
			return title;			
		}
		woas.log("No back history");
		return null;
	},
	
	forward: function() {
		if (forstack.length > 0) {
			going_forward = true;
			return forstack.pop();
		}
		woas.log("No forward history");
		return null;
	},
	
	go: function(title, keep_fwd) {
		if (!going_back && !woas.ui.edit_mode && current !== title) {
			store(current);
		}
		if (!keep_fwd && !going_forward && !going_back/* && !/^Lock::/.test(title)*/) {
			forstack = [];
		}
		going_back = going_forward = false;
	},
	
	// PVHL: this shouldn't be here, but needed for new pages by current design
	// store() should be an internal, private function
	store: function(title) {
		store(title);
	},

	// remove title if it exists. If no title given clear history
	// return false if title was given but not found (could be useful)
	clear: function(title) {
		if  (title && title.length) {
			// remove the deleted page from history
			var found = false, i, it;
			for (i = 0, it = backstack.length; i < it; ++i) {
				// remove also duplicate sequences
				if (backstack[i] === title) {
					found = true;
					backstack.splice(i, 1);
					// fix the loop
					--it;
					// iterate again to remove duplicate sequences
					--i;
				}
			}
			// delete also from forstack
			for (i = 0, it = forstack.length; i < it; ++i) {
				// remove also duplicate sequences
				if (forstack[i] === title) {
					found = true;
					forstack.splice(i,1);
					--it;
					--i;
				}
			}
			return found;
		} else {
			forstack = [];
			backstack = [];
			return true;
		}
	},
	
	// rename old_title; titles must be valid
	rename: function (old_title, new_title) {
		var i;
		for (i = 0; i < backstack.length; ++i) {
			if (backstack[i] === old_title) {
				backstack[i] = new_title;
			}
		}
		for (i = 0; i < forstack.length; ++i) {
			if (forstack[i] === old_title) {
				forstack[i] = new_title;
			}
		}
	},
	
	// use: woas.log(woas.history.log_entry())
	log_entry: function() {
		function frmt(arr) {
			var str = [], i;
			for (i = 0; i < arr.length; ++i) {
				str.push(arr[i]);
			}
			return str.join(" | ");
		}
		return "history" + (backstack.length ? " : " : " > ")
			+ frmt(backstack) + (backstack.length ? " > " : "")
			+ current + (forstack.length ? " | " : "")
			+ frmt(forstack.slice(0).reverse());
	}
}}());

// some general integrity tests - for debug purposes
woas.integrity_test = function() {
	woas.log("Starting integrity test"); //log:1
	// test integrity of data arrays
	var len = pages.length;
	if ((page_attrs.length != len) ||
			(page_titles.length != len) ||
			(page_mts.length != len)) {
			this.crash("FATAL: data arrays have mismatching length!\n"+
						"#pages = %d, #page_attrs = %d, #page_titles = %d, #page_mts = %d".
						sprintf(pages.length, page_attrs.length, page_titles.length,
						page_mts.length));
		return false;
	}
	// test integrity of ecma encoding for normal UTF-8
	var UTF8_TEST = "Di\u00e2critics are here: \u00e4 \u00e1y";
	if (this.ecma_decode(this.ecma_encode(UTF8_TEST)) !== UTF8_TEST) {
		this.crash("ECMA encoding not working:\n"+this.ecma_decode(this.ecma_encode(UTF8_TEST))+
		"\n"+UTF8_TEST);
		return false;
	}
	// test integrity of ecma encoding for 16bit UTF-8
	var UTF8_TEST2 = "\u30e9\u30c9\u30af\u30ea\u30d5";
	if (this.ecma_decode(this.ecma_encode(UTF8_TEST2)) !== UTF8_TEST2) {
		this.crash("ECMA encoding/decoding not working:\n"+this.ecma_decode(this.ecma_encode(UTF8_TEST2))+
		"\n"+UTF8_TEST2);
		return false;
	}
	// test integrity of load/save functions if not on remote server
	if (!this._server_mode) {
		if (!this.save_file(woas.ROOT_DIRECTORY+"itest.bin", this.file_mode.UTF8_TEXT,
				woas.utf8.encode(UTF8_TEST)
	//			UTF8_TEST
				)) {
			this.crash("Save failure during integrity test\n"+woas.ROOT_DIRECTORY);
			return false;
		}
		var ct = this.load_file(woas.ROOT_DIRECTORY+"itest.bin", this.file_mode.UTF8_TEXT);
		if ((ct === null)||(ct === false)) {
			if (ct === false)
				this.crash("Load failure during integrity test\n"+woas.ROOT_DIRECTORY);
			return false;
		}
		ct = woas.utf8.decode(ct);
		if (ct !== UTF8_TEST) {
			this.crash("UTF8 test failed.\nWritten:\n"+UTF8_TEST+"\nRead:\n"+ct);
			return false;
		}
	} else { // we are on a remote server
		woas.log("Skipping save integrity test because running from web server");	//log:1
		//TODO: remote load integrity test
	}
	// now test AES encryption
	woas.AES.setKey("WoaS");
	var testdata = "sample text here";
	var enc = woas.AES.encrypt(testdata);
	if (woas.AES.decrypt(enc) !== testdata) {
		this.crash("AES encryption is not working two-way!");
		woas.AES.clearKey();
		return false;
	}
	if (woas.AES.decrypt(woas.AES.encrypt(UTF8_TEST)) !== UTF8_TEST) {
		this.crash("AES encryption of UTF8 text is not working two-way!");
		woas.AES.clearKey();
		return false;
	}
	woas.AES.clearKey();
	woas.log("Integrity test successful"); //log:1
	return true;
};

// used in path normalization during export
woas.DIRECTORY_SEPARATOR = (navigator.appVersion.indexOf("Win")!=-1)?"\\":"/";

woas._dirname_regex = new RegExp("\\"+woas.DIRECTORY_SEPARATOR+"[^\\"+woas.DIRECTORY_SEPARATOR+"]*$");
woas._basename_regex = new RegExp("[\\\\/]([^\\\\/]+)$");		// "\\[\\\\/]([^\\\\/]+)$"

// hackish functions, might stay private for now
woas.dirname = function(fn) {
	return fn.replace(this._dirname_regex, woas.DIRECTORY_SEPARATOR);
};

woas.basename = function(fn) {
	var m = fn.match(this._basename_regex);
	if (m === null)
		return fn;
	return m[1];
};

// the export path used by export feature
woas.ROOT_DIRECTORY = woas.dirname(_get_this_filename());

//API1.0: get page attributes - can be overriden by plugins
//TODO: all code should use this function
woas.get_page_attrs = function(pi) {
	// no error check
	return page_attrs[pi];
};

//API1.0: set page attributes - can be overriden by plugins
//TODO: all code should use this function
woas.set_page_attrs = function(pi, attrs) {
	// no error check
	page_attrs[pi] = attrs;
	return true;
};

//API1.0: dynamically add a hotkey
// returns true if hotkey was added successfully or if already present
woas.add_hotkey = function(key, function_obj) {
	//FIXME: this needs to be finished!
};

woas.split_bytes = function(s) {
	var l=s.length;
	var arr=[];
	for(var i=0;i < l;i++)
		arr.push(s.charCodeAt(i));
	return arr;
};
	
woas.merge_bytes = function(byte_arr) {
	var l=byte_arr.length, s="";
	for(var i=0;i < l;i++) {
		s+=String.fromCharCode(byte_arr[i]);
	}
	return s;
};

var reReplaceBr = new RegExp("<"+"br\\s?\\/?>", "gi");
woas.xhtml_to_text = function(s) {
	return s.replace(reReplaceBr, "\n")
		.replace(/<\/?\w+[^>]*>/g, '')
		.replace(/&#?([^;]+);/g, function(str, $1) {
			return isNaN($1) ? '' : String.fromCharCode($1);
		});
};

// WoaS DOM manager
// all DOM modifications shall be indexed by this module
woas.dom = {
	// hashmap used to quickly reference some important DOM objects
	_cache: {},
	// DOM management area
	_objects: [],
	
	init: function() {
		this._cache.head = document.getElementsByTagName("head")[0];
		this._cache.body = document.getElementsByTagName("body")[0];
		if (woas.browser.ie)
			this._cache.stylesheet = document.styleSheets[0];
		else
			this._cache.stylesheet = document.getElementsByTagName("style")[0];
	},
	
	add_css: function(css_id, css_src, external, after_load) {
/*		if (document.createStyleSheet) {// check for MSIE
			this._cache.head.insertAdjacentHTML('beforeEnd',
				'<'+'span id="'+'" style="display:none">x<'+'/span>'  // MSIE needs this for some reason
				+ '<+'style id="'+'" type="text/css">'+css_text+'<'+'/style>');
			//TODO: check that style can then be properly removed
		  } else { */
		// always add this custom prefix
		css_id = "woas_css_"+css_id;
		
		// check if we have a duplicate instance
		if (this.index(css_id) !== -1) {
			woas.log("DOM: instance "+css_id+" already exists");
			return false;
		}
		
		var style;
		if (external) {
			style = document.createElement("link");
			style.setAttribute("rel", "stylesheet");
			style.setAttribute("type", "text/css");
			style.setAttribute("id", css_id);
			style.setAttribute("href", css_src);
			// only when external
			++this._loading;
		} else {
			style = document.createElement('style');
			style.type = "text/css";
			style.id = css_id;
			style.appendChild(document.createTextNode(css_text));
		}
		
		this._objects.push( {obj:style, parent: (woas.browser.ie ? this._cache.body:this._cache.head),
							instance:css_id, after_load: external ? after_load : null } );
		
		woas.log("DOM: "+css_id+" created "+this._show_load());
		// add a callback which informs us of the completion (not always possible)
		if (external) {
			// these engines don't support a callback :(
			if (woas.browser.gecko || woas.browser.webkit) {
				setTimeout("woas.dom._elem_onload('"+woas.js_encode(css_id)+"');", 100);
			} else { // good ol' IE
				style.onreadystatechange = woas._make_delta_func("woas.dom._elem_onload",
													"'"+woas.js_encode(css_id)+"'");
			}
		}
		
		// on IE inject directly in body
		if (woas.browser.ie) {
			this._cache.body.appendChild(style);
		} else {
			this._cache.head.appendChild(style);
		}
		return true;
	},
	
	remove_css: function(i) {
		return this.remove("woas_css_"+i);
	},

	remove_script: function(script_class, script_id) {
		return this.remove("woas_script_"+script_class+"_"+script_id);
	},
	
	remove: function(instance) {
		var found = this.index(instance);
		if (found === -1)
			return false;
		// delete DOM entry from parent container
		this._objects[found].parent.removeChild(this._objects[found].obj);
		// fix arrays
		this._objects.splice(found, 1);
		return true;
	},
	
	// counter of elements being loaded
	_loading: 0,
	
	// generic callback used when we want to run something after the file has been loaded
	// (usually CSS/JavaScript)
	_elem_onload: function(instance) {
		// go away if it is already loaded
		if (woas.dom.get_loaded(instance))
			return;
		// only for IE
		if (woas.browser.ie && (typeof this.readyState != "undefined")) {
			if (this.readyState != 'complete' && this.readyState != 'loaded')
				return;
			// remove handler
			this.onreadystatechange = null;
		} else if (woas.browser.firefox) {
		  // unplug handler
		  var dom_obj = woas.dom._objects[woas.dom.index(instance)];
		  dom_obj.obj.onload = null;
		}
		// set as loaded (shall not remove from arrays)
		woas.dom.set_loaded(instance);
	},
	
	get_loaded: function(instance) {
		var i = this.index(instance);
		if (i !== -1) {
			if (this._objects[i].instance === instance)
				return this._objects[i].loaded;
		}
		woas.log("DOM: "+instance+" is not indexed"+this._show_load());
		return false;
	},
	
	// get list of instances which are still loading
	get_loading: function() {
		var a=[];
		for(var i=0,it=this._objects.length;i < it;++i) {
			if (!this._objects[i].loaded)
				a.push(this._objects[i].instance);
		}
		return a;
	},
	
	// short-hand to get index of an instance
	index: function(instance) {
		for(var i=0,it=this._objects.length;i < it;++i) {
			if (this._objects[i].instance === instance)
				return i;
		}
		return -1;
	},

	set_loaded: function(instance) {
		var i = this.index(instance);
		if (i !== -1) {
			this._objects[i].loaded = true;
				
			// now call the associated callback
			if (typeof this._objects[i].after_load == "function") {
				(this._objects[i].after_load)();
			}
			
			// reduce the counter of 'hung' requests
			--this._loading;
			woas.log("DOM: "+instance+" completed loading"+this._show_load());
			// check if we need to launch the hook
			if (this._loading === 0)
				this._run_post_load_hook();
			
			return true;
		}
		woas.log("DOM: "+instance+" completed loading, but was not indexed"+this._show_load());
		return false;
	},
	
	_show_load: function() {
		return "";
/*		return " (%d/%d)".sprintf(this._loading, this._objects.length)+"\n"+
				"still loading: "+this.get_loading();
*/
	},
	
	// regex used to remove some comments
	reJSComments: /^\s*\/\*[\s\S]*?\*\/\s*/g,
	
	_internal_add: function(script_token, script_content, external, after_load) {
		script_token = "woas_script_"+script_token;
		// check if we have a duplicate instance
		if (this.index(script_token) !== -1) {
			woas.log("DOM: instance "+script_token+" already exists");
			return false;
		}
		
		var s_elem = document.createElement("script");
		s_elem.type="text/javascript";
		s_elem.id = script_token;

		// register in our management arrays
		this._objects.push( {obj:s_elem, parent:this._cache.head, instance:script_token,
								external: external ? true : false,
								loaded: external ? false : true, after_load: external ? after_load : null} );
		// only external sources should be marked as "loading"
		if (external)
			++this._loading;
		woas.log("DOM: "+script_token+" created "+(external ? "("+script_content+") ":"(inline) ")+this._show_load());
		// add a callback which informs us of the completion
		if (external) {
			if (woas.browser.ie)
				s_elem.onreadystatechange = woas._make_delta_func("woas.dom._elem_onload",
													"'"+woas.js_encode(s_elem.id)+"'");
			else
				s_elem.onload = woas._make_delta_func("woas.dom._elem_onload",
													"'"+woas.js_encode(s_elem.id)+"'");
			// specify the external URL
			s_elem.src = script_content;
		}
				
		this._cache.head.appendChild(s_elem);
		if (!external) {
//			woas.alert("Inline code:\n"+script_content);
			woas.setHTML(s_elem, script_content);
		}
		return true;
	},
	
	add_script: function(script_class, script_id, script_content, external, after_load) {
		// remove the comments
		if (!external)
			script_content = script_content.replace(this.reJSComments, '');
		// it's not necessary to add this script tag
		if (!script_content.length) return false;
		return this._internal_add(script_class+"_"+script_id, script_content, external, after_load);
	},
	
	// remove all script objects
	remove_all: function() {
		var it=this._instances.length;
		for(var i=0;i < it;++i) {
			// remove the object
			this._objects[i].parent.removeChild(this._objects[i].obj);
		}
		// clear objects array
		this._objects = [];
	},
	
	// call the argument function when there aren't other libraries left to load
	// returns true if loading was already complete
	// returns false if we are async-waiting
	_post_load_hook: woas._dummy_fn,
	wait_loading: function(fn_object) {
		if (this._loading === 0) {
			(fn_object)();
			// always reset associated async hook
			this._post_load_hook = woas._dummy_fn;
			return true;
		}
		// associate the hook
		this._post_load_hook = fn_object;
		return false;
	},
	
	_run_post_load_hook: function() {
		// run in a thread so that the call to last object unload does not wait on the hook
		setTimeout('woas.dom._post_load_hook();woas.dom._post_load_hook=woas._dummy_fn;', 10);
	}
	
};

// generate a delta function and cache it
woas._delta_cache = {};
woas._make_delta_func = function(fn_name, fn_args) {
	var id=fn_name+' '+fn_args;
	var fn_obj;
	if (typeof woas._delta_cache[id] == "undefined") {
		eval("fn_obj = function() { "+fn_name+"("+fn_args+"); };");
		woas._delta_cache[id] = fn_obj;
	} else
		fn_obj = woas._delta_cache[id];
	return fn_obj;
};

// @module pager
woas.pager = {

	_decrypt_failed: false,	// the last decryption failed due to wrong password attempts
	
	decrypt_failed: function() {
		if (this._decrypt_failed) {
			this._decrypt_failed = false;
			return true;
		}
		return false;
	},

	get: function(title) {
		return woas.get_text(title);
	},
	
	get_by_index: function(i) {
		return woas.get__text(i);
	},
	
	// this yummy function needs can be overriden
	// Determines if page 'title' is allowed to be loaded by woas.set_current
	// return false to block the page from being loading, true to allow.
	browse_hook: function(title) {
		return true;
	},
	
	// set content of specified page
	set_body: function(title, new_body) {
		var pi = woas.page_index(title);
		if (woas.debug_mode) {
			if (pi === -1) {
				woas.log("BUG: page \""+title+"\" does not exist!");	// log:1
				return;
			}
		}
		woas.set__text(pi, new_body);
	}
};

// @module pager.bucket
woas.pager.bucket = {
	items: [],		// multi-pages selection
	clear: function() {
		this.items = [];
	},
	add: function(title) {
		if (this.items.indexOf(title) === -1)
			this.items.push(title);
	},
	// used when we want to set a single page in bucket
	one: function(title) {
		this.items = [title];
	}
};

// namespace for custom stuff defined by macros/plugins
// if you are a JavaScript developer you should put singleton instance objects in here
woas.custom = { };

/*** src/stickwiki.js ***/
// the namespace(+subnamespaces) of the current page
woas.current_namespace = "";

// the last page on which the cached AES key was used on
woas.last_AES_page = "";

// tells if configuration has been changed
woas.cfg_changed = false;

// new variables will be properly declared here
woas.prev_title = current;		// previous page's title used when entering/exiting edit mode

woas.save_queue = [];		// pages which need to be saved and are waiting in the queue

// Auto-Save Thread
woas._autosave_thread = null;

// this will likely happen when javascript code block was corrupted
woas._on_load = woas_on_unload = function() { this.crash("Deferred load/unload function not available!");};

// default post-load hook
woas.post_load = function(){};

// left and right trim
// grabbed from http://blog.stevenlevithan.com/archives/faster-trim-javascript
woas.trim = function(str) {
//	return s.replace(/(^\s*)|(\s*$)/, '');
	str = str.replace(/^\s+/, '');
	for (var i = str.length - 1; i >= 0; i--) {
		if (/\S/.test(str.charAt(i))) {
			str = str.substring(0, i + 1);
			break;
		}
	}
	return str;
};

// used to craft XHTML pages
woas.DOCTYPE = "<"+"!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n";
woas.DOC_START = "<"+"html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<"+"head>\n"+
	"<"+"meta woas_permanent=\"1\" http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";

// general javascript-safe string quoting
// NOTE: not completely binary safe!
// should be used only for titles (which ought not to contain binary bytes)
var reMinorG = new RegExp("<", "g");
woas.js_encode = function (s, split_lines) {
	// not to counfound browsers with saved tags
	s = s.replace(/\\/g, "\\\\").replace(reMinorG, "\\x3C").replace(/>/g, "\\x3E").
		replace(/'/g, "\\'");
	// escape newlines (\r\n happens only on the stupid IE) and eventually split the lines accordingly
	if (!split_lines)
		s = s.replace(new RegExp("\r\n|\n", "g"), "\\n");
	else
		s = s.replace(new RegExp("\r\n|\n", "g"), "\\n\\\n");
	return this._utf8_js_fix(s);
};

// perform ECMAScript encoding only on some UTF-8 sequences
woas.ecma_encode = function(s) {
	return this._utf8_js_fix(s.replace(/\\/g, "\\\\"));
};

woas._ecma_rx_test = new RegExp("[^\u0000-\u007F]");

// returns true if text needs ECMA encoding
// checks if there are UTF-8 characters
woas.needs_ecma_encoding = function(s) {
	return this._ecma_rx_test.test(s);
};

woas._utf8_js_fix = function(s) {
	// fix the >= 128 ascii chars (to prevent UTF-8 characters corruption)
	return s.replace(woas.utf8.reUTF8Space, function(str) {
		var r="";
		for(var a=0,l=str.length;a < l;++a) {
			var s = str.charCodeAt(a).toString(16);
			r += "\\u" + "0000".substr(s.length) + s;
		}
		return r;
	});
};

woas.ecma_decode = function(s) {
	return s.replace(new RegExp("(\\\\u[0-9a-f]{4})+", "g"), function (str, $1) {
		// this will perform real UTF-8 decoding
		var r = "";
		for (var ic=0,totc=str.length;ic < totc;ic+=6) {
			// get the hexa-numeric part
			var c = str.substr(ic+2, 4);
			// remove leading zeroes and convert to base10
			c = parseInt(c.replace(/^0*/,''), 16);
			// convert UTF-8 sequence to character
			r += String.fromCharCode(c);
		}
		return r;
	}).replace(/\\\\/g, "\\");
};

// used to escape blocks of source into HTML-valid output
woas.xhtml_encode = function(src) {
	return this.utf8.do_escape(src.replace(/&/g, '&amp;').replace(reMinorG, '&lt;').
			replace(/>/g, '&gt;')); // .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
};

// DO NOT modify this list! these are namespaces that are reserved to WoaS
var reserved_namespaces = ["Special", "WoaS", "Lock", "Locked", "Unlocked",
		"Unlock", "Tags?", "Tagged", "Untagged", "Include", "Javascript"];

// create the regex for reserved namespaces
var reserved_rx = "^(?:";
for(var i = (woas.tweak.edit_override ? 2 : 0);i < reserved_namespaces.length - 1;i++) {
	reserved_rx += reserved_namespaces[i] + "|";
}
reserved_rx += reserved_namespaces[i] + ")::";
woas._reserved_rx = new RegExp(reserved_rx, "i");
reserved_namespaces = reserved_rx = null;

// return page index (progressive number) given its title
woas.page_index = function(title) {
	return page_titles.indexOf(this.title_unalias(title));
};

woas.is_reserved = function(page) {
	return (page.search(this._reserved_rx) == 0);
};

woas.is_menu = function(title) {
	return title.substr(-6) === '::Menu' && title !== 'WoaS::Help::Menu';
};

// returns namespace with trailing ::
woas.get_namespace = function(page, root_only) {
	var	p = root_only ? page.indexOf("::") : page.lastIndexOf("::");
	return p === -1 ? "" : page.substring(0, p + 2);	
};

// page attributes bits are mapped to (readonly, encrypted, ...)

woas.is_readonly = function(page) {
	return this.is_readonly_id(this.page_index(page));
};

woas.is_readonly_id = function(pi) {
	return !!(page_attrs[pi] & 1);
};

woas.is__encrypted = function (pi) {
	return !!(page_attrs[pi] & 2);
};

woas.is_encrypted = function(page) {
	return this.is__encrypted(this.page_index(page));
};

woas.is__embedded = function(pi) {
	return !!(page_attrs[pi] & 4);
};
woas.is_embedded = function(page) {return this.is__embedded(this.page_index(page));};

woas.is__image = function(pi) {
	return !!(page_attrs[pi] & 8);
};
woas.is_image = function(page) { return this.is__image(this.page_index(page)); };

// a page physically exists if it is not part of a reserved namespace, if it is not a (sub)namespace and if it actually exists
// PVHL: the above description doesn't seem to work anymore. For this function a page exists if
// clicking on it would produce a page; e.g. a real or dynamic page. A listing page always
// produces a page, as does an entry in pages. For WoaS and Special it depends on edit_override
// whether is_reserved is accurate. Need to check properly.
woas.page_exists = function(page) {
//	return (this.is_reserved(page) || (page.substring(page.length-2)==="::") || (this.page_index(page)!==-1));
	var exists = false, s = /^Special::/, w = /^WoaS::/;
	exists = ((page.substring(page.length-2)==="::") || (this.page_index(page)!==-1));
	if (!exists && this.is_reserved(page) && !(s.test(page) || w.test(page))) {
		exists = true;
	}
	if (!exists && s.test(page)) {
		for (i = 0; i < this.shortcuts.length; ++i) {
			if (page.substr(9) === this.shortcuts[i]) {
				exists = true;
				break;
			}
		}
	}
	return exists;
};

// with two trailing colons 'xx::'
woas._get_namespace_pages = function (ns) {
	var pg = [], i, l;
	switch (ns.substr(0, ns.indexOf('::'))) {
	case "Locked":
		return this.special_encrypted_pages(true);
	case "Unlocked":
		return this.special_encrypted_pages(false);
	case "Untagged":
		return this.special_untagged();
	case "Tagged": // to be used in wiki source
		return this.special_tagged();
	case "Image":
		return this._special_image_gallery(ns);
	case "Special":
		for (i = 0; i < this.shortcuts.length; ++i) {
				pg.push(ns + this.shortcuts[i]);
		}
		for(i = 0, l = page_titles.length; i < l; ++i) {
			if (page_titles[i].indexOf(ns) === 0
					// don't show pages used by special functions unless override
					&& (woas.tweak.edit_override ||
					(page_titles[i] !== 'Special::Embed' && page_titles[i] !== 'Special::Lock'))){
				pg.push(page_titles[i]);
			}
		}
		return this._join_list(pg);
	case "Tag":
	case "Tags":
	case "Include":
	case "Lock":
	case "Unlock":
	case "Javascript":
		// these should not be viewed as a namespace
		return woas.i18n.NOT_A_NS.sprintf(ns);
	}

	for(i = 0, l = page_titles.length; i < l; ++i) {
		if (page_titles[i].indexOf(ns) === 0)
			pg.push(page_titles[i]);
	}
	return !pg.length ? woas.i18n.EMPTY_NS.sprintf(ns) : this._join_list(pg);
};

// return a plain page or a decrypted one if available through the latest key
woas.get_page = function(pi) {
	if (this.is__embedded(pi))
		return null;
	if (!this.is__encrypted(pi))
		return pages[pi];
	if (!this.AES.isKeySet()) {
		this.last_AES_page = "";
		return null;
	}
	// decrypt by using a copy of the array
	var pg = this.AES.decrypt(pages[pi].slice(0));
	this.last_AES_page = page_titles[pi];
	return pg;	
};

var reScriptTags = new RegExp("<"+"script[^>]*>((.|\\n)*?)<"+"\\/script>", "gi"),
	reAnyXHTML = /\<\/?\w+[^>]+>/g;
// get the text of the page, stripped of html tags
woas.get_src_page = function(pi, rawmode) {
	var pg = this.get_page(pi);
	if (pg===null) return null;
	if ((typeof rawmode == "undefined") || (rawmode == false))
		pg = pg.replace(/\{\{\{((.|\n)*?)\}\}\}/g, "");
	else
		pg = pg.replace(/(\{|\})(\1)(\1)/g, "$1<"+"!-- -"+"->$2<"+"!-- -"+"->$3");
	// remove wiki and html that should not be viewed when previewing wiki snippets
	return pg.replace(reScriptTags, "").
			replace(reAnyXHTML, "");
};

woas.get_text = function (title) {
	var pi = this.page_index(title);
	if (pi==-1)
		return null;
	return this.get__text(pi);
};

woas.get_text_special = function(title) {
	var ns = this.get_namespace(title);
	var text = null;
	if (ns.length) {
//		woas.log("namespace of "+title+" is "+namespace);	// log:0
		title = title.substring(ns.length);
		if (!title.length) return this._get_namespace_pages(ns);
		switch (ns) {
			case "Special::":
				text = this._get_special(title, false);
				if (text === false) text = null;
			break;
			case "Tagged::":
				text = this.special_tagged(title);
			break;
			default:
				text = this.get_text(ns+title);
		}
	} else
		text = this.get_text(title);
	return text;
};

woas.__last_title = null;

woas.__password_finalize = function(pwd_obj) {
	document.title = this.__last_title;
	this.ui.display({pswd:false});
	// hide input form
	pwd_obj.value = "";
	pwd_obj.blur();
	this.ui.blur_textbox();
};

woas._set_password = function() {
	this.__last_title = document.title;
	document.title = "Enter password";
	// hide browser scrollbars and show mask
	this.ui.display({pswd:true});
	d$("woas_password").focus();	
	this.ui.focus_textbox();
};

woas._password_cancel = function() {
	this.__password_finalize(d$("woas_password"));
};

// PVHL: input now accepts password if enter has been pressed
//   will redo to use key callback function later
woas._password_ok = function(el, e) {
	// test for enter key pressed
	var flag = e ? e.keyCode === 13 : true, pw;
	if (flag) {
		pw = el.value;
		if (!pw.length) {
			this.alert(this.i18n.PWD_QUERY);
		} else {
			this.AES.setKey(pw);
			this.__password_finalize(el);
		}
	}
	return true;
};

//TODO: specify interactive-mode
woas.get__text = function(pi) {
	// is the page encrypted or plain?
	if (!this.is__encrypted(pi))
		return pages[pi];
	this.pager._decrypt_failed = true;
	if (!this.AES.isKeySet()) {
		this.alert(this.i18n.ERR_NO_PWD.sprintf(page_titles[pi]));
		return null;
	}
	this.progress_init("AES decryption");
//	var pg = null;
			//TODO: use form-based password input
//			this._get_password('The latest entered password (if any) was not correct for page "'+page_titles[pi]+"\"");
//			var pw = prompt('The latest entered password (if any) was not correct for page "'+page_titles[pi]+"'\n\nPlease enter the correct password.", '');
//			if ((pw==null) || !pw.length) {
			// we are waiting for the password to be set programmatically
/*			if (!pw.length) {
				this.last_AES_page = "";
				AES_clearKey();
				document.body.style.cursor = "auto";
				return null;
			}
			AES_setKey(pw);
			retry++;
*/
//			return null;
//		}
		// pass a copied instance to the decrypt function
		// AES_decrypt can return null on failure, but can also return a garbled output
		var pg = this.AES.decrypt(pages[pi].slice(0));
		this.last_AES_page = page_titles[pi];
//		if (pg != null)
//			break;
	if (!this.config.key_cache)
		this.AES.clearKey();
	if (pg !== null) {
		this.pager._decrypt_failed = false;
//		if (this.config.key_cache)			this.last_AES_page = page_titles[pi];
	} else {
		this.alert(this.i18n.ACCESS_DENIED.sprintf(page_titles[pi]));
//		AES_clearKey();
		this.last_AES_page = "";
	}
	this.progress_finish();
	return pg;
};

woas.set__text = function(pi, text) {
	this.log("Setting wiki text for page #"+pi+" \""+page_titles[pi]+"\"");	// log:1
	if (this.is__embedded(pi) && !this.is__image(pi))
		text = this.base64.encode(text);
	if (!this.is__encrypted(pi)) {
		pages[pi] = text;
		return;
	}
	pages[pi] = this.AES.encrypt(text);
	this.last_AES_page = page_titles[pi];
};

woas.assert_current = function(page) {
	if( current !== page )
		this.go_to( page ) ;
	else
		this.set_current( page, true);
};

woas._get_embedded = function(cr, etype) {
	var pi = this.page_index(cr);
	if (pi === -1) {
		var P = {body:this.parser.transclude("Special::Embed|"+etype, [])};
		this.parser.syntax_parse(P, []);
		return P.body;
	}
	return this._get__embedded(cr, pi, etype);
};

woas._get__embedded = function (cr, pi, etype) {
	var text=this.get__text(pi);
	if (text==null) return null;
	var xhtml = "";
	
	if (etype=="file") {
		var fn = cr.substr(cr.indexOf("::")+2);
		var pview_data = this.base64.decode(text, 1024), pview_link = "",
			ext_size = Math.ceil((text.length*3)/4);
		//FIXME: is this even correct?
		if (ext_size-pview_data.length>10)
			pview_link = "<"+"div id='_part_display'><"+"em>"+this.i18n.FILE_DISPLAY_LIMIT+
			"<"+"/em><"+"br /><"+"a href='javascript:show_full_file("+pi+")'>"+this.i18n.DISPLAY_FULL_FILE+"<"+"/a><"+"/div>";
		var P = {body: "\n{{{[[Include::"+cr+"]]}}}"+
				"\n\nRaw transclusion:\n\n{{{[[Include::"+cr+"|raw]]}}}"};
		if (!this.is_reserved(cr))
			P.body += "\n\n\n<"+"a href=\"javascript:query_delete_file('"+this.js_encode(cr)+"')\">"+this.i18n.DELETE_FILE+"<"+"/a>\n";
		P.body += "\n";
		
		// correct syntax parsing of nowiki syntax (also does macros and XHTML comments)
		var snippets = [];
		this.parser.pre_parse(P, snippets);
		this.parser.syntax_parse(P, snippets);
		
		xhtml = this.parser._raw_preformatted("pre", pview_data, 'woas_embedded')+
			pview_link+"<"+"br /><"+"hr />"+this.i18n.FILE_SIZE+": "+_convert_bytes(ext_size)+
			"<"+"br />" + this.last_modified(this.config.store_mts ? page_mts[pi] : 0)+
			"<"+"br /><"+"br />XHTML transclusion:"+P.body+
			"<"+"a onClick=\"query_export_file('"+this.js_encode(cr)+"')\">"+this.i18n.EXPORT_FILE+
			"<"+"/a><"+"br />";
		P = null;
	} else { // etype == image
		// PVHL: modified to handle errors and remove export where not possible
		// TODO: replace all text with i18n strings; add 'get Firefox' link
		//   this all needs to be coming from pages that can be formatted
		//   can be much improved -- just to get it working right now.
		// Can also load dynamically from page -- allows error gathering.
		// Those browsers that can't embed should not be shown an embed page.
		var img_name = cr.substr(cr.indexOf("::")+2), ff = this.browser.firefox,
			mime = text.match(/^data:\s*([^;]+);/)[1],
			tot_len = text.length,
			enc_len = text.match(/^data:\s*[^;]*;\s*[^,]*,\s*/)[0].length,
			mts = (this.config.store_mts ? page_mts[pi] : 0 ),
			fn = "=\"_img_properties_show('"+mime+"',"+tot_len+","+enc_len+","+mts,
			load = this.browser.ie6
				? 'class="woas_hide" />/This browser can\'t display images yet./'+"\n\n"+
				  woas.i18n.MIME_TYPE+": "+mime+"\n"+woas.i18n.FILE_SIZE+": about "+
				  _convert_bytes(((tot_len-enc_len)*3)/4, 1)+
				  woas.i18n.B64_REQ.sprintf(_convert_bytes(tot_len, 1))+
				  "\n"+woas.last_modified(mts)
				: "onload"+fn+")\"; onerror"+fn+",true)\" /><"+
				"div id=\"woas_img_desc\">"+this.i18n.LOADING+"<"+"/div>";
		xhtml = this.parser.parse("= "+img_name+"\n\n\n"+"<"+"img id=\"woas_img_tag\" src=\""+
			text+"\" alt=\""+this.xhtml_encode(img_name)+"\" "+load+
			"\n\nSimple transclusion:\n\n{{{[[Include::"+cr+
			"]]}}}\n\nTransclusion with additional attributes:\n\n{{{[[Include::"+cr+
			"|border=\"0\" onclick=\"woas.go_to('"+this.js_encode(cr)+
			"')\" style=\"cursor:pointer\"]]}}}\n\n<"+"a onClick=\"query_delete_image('"+
			this.js_encode(cr)+"')\" class=\"woas_link\">"+this.i18n.DELETE_IMAGE+"<"+"/a>\n"+
			(ff ? "\n<"+"a id=\"woas_img_export\" onClick=\"query_export_image('"+
			this.js_encode(cr)+"')\" class=\"woas_link\">"+this.i18n.EXPORT_IMAGE+"<"+"/a>\n"
			: '\n/This browser can\'t export images yet: *get Firefox!* /'));
	}
	return xhtml;
};

woas._embed_process = function(etype) {
	// pick the correct mode for file inclusion
	// normalize etype to the correspondant binary flag value
	var desired_mode;
	if (etype == "image") {
		desired_mode = this.file_mode.DATA_URI;
		etype = 12;
	} else {
		desired_mode = this.file_mode.BASE64;
		etype = 4;
	}

	// load the data in DATA:URI mode
	var ct = this.load_file(null, desired_mode);
	if ((ct === false) || ((typeof ct != "string") || !ct.length)) {
		this.alert(this.i18n.LOAD_ERR);
		return false;
	}

	pages.push(ct);
	page_attrs.push(etype);
	page_titles.push(current);
	// set modified timestamp to now
	page_mts.push(this.config.store_mts ? Math.round(new Date().getTime()/1000) : 0);
	
	// save this last page
	this.commit([page_titles.length-1]);
	
	return this.set_current(current, true);
};

woas._get_special = function(cr, interactive) {
	var text = null;
	var pi = this.shortcuts.indexOf(cr);
	cr = "Special::" + cr;
	if (pi != -1) {
		var fn = this.shortcuts_js[pi];
		var is_cmd = (fn.substr(0,4)=="cmd_");
		if (!interactive && is_cmd)
			return null;
		text = this[fn]();
		// skip the cmd shortcuts
		if (is_cmd)
			// return a special value for executed commands
			return false;
	} else
		text = this.get_text(cr);
	if(text === null) {
		if (interactive)
			this.alert(this.i18n.INVALID_PAGE.sprintf('Special'));
	}
	return text;
};

woas.get_javascript_page = function(cr) {
	var text = woas.eval(cr, true);
	if (this.eval_failed) {
		woas.log(this.i18n.JS_PAGE_FAIL1.sprintf(cr) +
			this.i18n.JS_PAGE_FAIL2 + this.eval_fail_msg);
		return null;
	}
	// safety check; returned value contains 'body' or ['title', 'body']
	// body can be null if type is not array, otherwise type must be array and
	// title can be empty, but body must exist (dynamic page creation)
	if ((typeof text) === "undefined" ||
			(!(text instanceof Array) && (typeof text) === "string") ||
			((text instanceof Array) && text.length === 2 &&
				(typeof text[0]) === 'string' && (typeof text[1]) === 'string'
				&& text[1])) {
		return text || null;
	}
	this.log(this.i18n.JS_PAGE_FAIL1.sprintf(cr) + this.i18n.JS_PAGE_FAIL3
		.sprintf(text, text instanceof Array ? 'array' : typeof text));
	return null;
};

woas.eval = function(code, return_value) {
	var rv;
	try {
		if (return_value)
			eval("rv = "+code);
		else
			eval(code);
		woas.eval_failed = false;
	}
	catch (e) {
		this.eval_fail_msg = e.toString();
		this.eval_failed = true;
	}
//	woas.log("woas.eval(\""+code+"\", "+return_value+") = "+rv);	//log:0
	return rv;
};

// Load a new current page
// return true if page was successfully loaded
// PVHL: needs to handle section references;
//   no_history added for Lock/Unlock/Options, etc. to stop history problems
woas.set_current = function (cr, interactive, keep_fwd) {
	// pager.browse_hook determines if cr is allowed to be set
	if (!woas.pager.browse_hook(cr))
		return false;
//	this.log("Setting current page to \""+cr+"\"");	//log:0
	var text, namespace, pi,
		// whether to reset bucket or not
		set_b = false;
	woas.pager.bucket.clear();
	// eventually remove the previous custom script
	if (cr.substring(cr.length-2)==="::") {
		text = this._get_namespace_pages(cr);
		namespace = cr.substring(0,cr.length-2);
		cr = "";
	} else {
		var p = cr.indexOf("::");
		// skip not found references but also null namespace references
		if (p>0) {
			namespace = cr.substring(0,p);
//			this.log("namespace of "+cr+" is "+namespace);	// log:0
			cr = cr.substring(p+2);
				switch (namespace) {
					case "Javascript":
						// this namespace may deprecate many others
						text = this.get_javascript_page(cr);
						if (text === null) {
							return false;
						} else if (text instanceof Array) {
							// allows function to return [title, body]
							if (!text[1]) {
								return false;
							}
							// title allowed to be empty string: 'Javascript::'
							cr = text[0] || '';
						}
						break;
					case "Special":
						text = this._get_special(cr, interactive);
						//the 'false' special value is returned in case of command execution
						if (text === false)
							return true;
						// no such special page exists
						if (text === null)
							return false;
						break;
					case "Tagged":
						text = this.special_tagged(cr);
						if (text === null)
							return false;
						break;
					case "Lock":
						// prevent special pages from being locked
						if (this.is_reserved(cr)) {
							this.alert(this.i18n.CANNOT_LOCK_RESERVED);
							return false;
						}
						this.currently_locking = this.js_encode(cr);
						pi = this.page_index(cr);
						if (this.AES.isKeySet()) {
							// display a message
							if (confirm(this.i18n.CONFIRM_LOCK.sprintf(cr)+
								(this.last_AES_page ? this.i18n.CONFIRM_LOCK_LAST
									.sprintf(this.last_AES_page) : ''))) {
								this._finalize_lock(pi);
								return false;
							}
						}
						text = this.get_text("Special::Lock");
						break;
					case "Unlock":
						pi = this.page_index(cr);
						// PVHL: Just a preventive; could be a bug: only unlock if locked;
						//   maybe the wrong place but OK for now
						if (pi !== -1 && (page_attrs[pi] & 0x2)) {
							if (!confirm(this.i18n.CONFIRM_REMOVE_ENCRYPT.sprintf(cr)))
								return false;
							text = this.get_text(cr);
							if (this.pager.decrypt_failed())
								return false;
							pages[pi] = text;
							page_attrs[pi] ^= 0x2;
							if (!this.config.key_cache)
								this.AES.clearKey();
							if (this.set_current(cr, true, true)) {
								this.save_page(cr);
								return true;
							}
						}
						return false;
					case "WoaS":
						pi = woas.page_index(namespace+"::"+cr);
						// unexisting page
						if (pi === -1) {
							if (interactive) {
								this.alert(this.i18n.INVALID_PAGE.sprintf('WoaS'));
							}
							return false;
						}
						var real_t = page_titles[pi];
/*						if (this.is__embedded(pi)) {
							//TODO: do not use namespace to guess the embedded file type
							text = this._get__embedded(real_t, pi, "file");
						} else { */
						// detect if showing a plugin
						var _pfx = "WoaS::Plugins::";
						if (real_t.substr(0, _pfx.length) === _pfx) {
							text = this.plugins.get(real_t.substr(_pfx.length));
							if (text !== null) {
								if (this.plugins.is_external) {
									text = this.plugins.describe_external(text);
								} else
									text = this.parser._raw_preformatted('pre', text,
										'woas_core_page');
							}
						} else {
							text = this.get_text(real_t);
							if (text !== null) {
								switch (cr) {
									case "Plugins":
										text = this.parser.parse(text + this.plugins.list());
									break;
									case "Aliases":
									case "Hotkeys":
									case "CSS::Core":
									case "CSS::Boot":
									case "CSS::Custom":
										// page is stored plaintext
										text = this.parser._raw_preformatted('pre', text,
											'woas_core_page');
									break;
									default:
										// help pages and related resources
										text = this.parser.parse(text);
								} // switch per page title
							} // text not null
						} // plugins/non-plugins

						if(text === null) {
							// called for reset purposes
							this.pager.decrypt_failed();
							return false;
						}
						if (namespace.length)
							cr = real_t;
						return this.load_as_current(cr, text, this.config.store_mts ? page_mts[pi] : 0, true);
					case "File":
					case "Image":
						text = this._get_embedded(namespace+"::"+cr, namespace.toLowerCase());
						if(text === null) {
							// called for reset purposes
							this.pager.decrypt_failed();
							return false;
						}
						if (namespace.length)
							cr = namespace + "::" + cr;
						var mts;
						if (this.config.store_mts)
							mts = page_mts[this.page_index(namespace+"::"+cr, namespace.toLowerCase())];
						else mts = 0;
						return this.load_as_current(cr, text, mts, true);
					default:
						text = this.get_text(namespace+"::"+cr);
						set_b = true;
				}

		} else {
			namespace = "";
			text = this.get_text(cr);
			set_b = true;
		}
	}
	
	// action taken when no such page exists (or decryption failed)
	if (text === null) {
		if (this.pager.decrypt_failed())
			return false;
		return this._new_page(this.i18n.PAGE_NOT_FOUND, false, namespace.length ? namespace+ "::"+ cr : cr);
	}
	
	// hard-set the current page to the namespace page
	if (namespace.length) {
		cr = namespace + "::" + cr;
		pi = this.page_index(cr);
		if (pi)
			mts = page_mts[pi];
		else mts = null;
	} else {
		pi = this.page_index(cr);
		cr = page_titles[pi];
		mts = page_mts[pi];
	}
	return this.load_as_current(cr, this.parser.parse(text, false, this.js_mode(cr)),
		this.config.store_mts ? mts : 0, set_b, keep_fwd);
};

// enable safe mode for non-reserved pages
woas.js_mode = function(cr) {
	return this.config.safe_mode && !this.is_reserved(cr) ? 3 : 1;
};

// no is optional; used by recently modified page
woas.last_modified = function(mts, no) {
	// do not show anything when the timestamp is magic (zero)
	if (mts == 0)
		return "";
	return (no ? "" : this.i18n.LAST_MODIFIED) + (new Date(mts*1000)).toLocaleString();
};

// actually load a page given the title and the proper XHTML
woas.load_as_current = function(title, xhtml, mts, set_b, keep_fwd) {
	if (typeof title == "undefined") {
		this.crash("load_as_current() called with undefined title");
		return false;
	}
	if (title.indexOf("Lock::") !== 0) {
		this.currently_locking = '';
	}
	
	// used by some special pages (e.g. backlinks) for page title override
	this.parser.render_title = title;
	// the bucket will contain only the rendered page
	if (set_b)
		this.pager.bucket.one(title);
	this.ui.top();
//	this.log("load_as_current(\""+title+"\", "+set_b+") - "+(typeof xhtml == "string" ? (xhtml.length+" bytes") : (typeof xhtml)));	// log:0
	this.setHTMLDiv(d$("woas_page"), xhtml);
	this.refresh_mts(mts);
	this.history.go(title, keep_fwd);
	current = title;
	this.ui.refresh_menu();
	// activate menu or page scripts
// PVHL: FIX - menu can be activated twice
	this.scripting.activate(this.is_menu(current) ? "menu" : "page");
	this._set_title(title);
	this.update_view();
	//this.log(this.history.log_entry());	// log:0
//if (console) console.log('load_as_current: ' + this.history.log_entry());
	return true;
};

woas._finalize_lock = function(pi, back) {
	this._perform_lock(pi);
	var title = page_titles[pi];
	if (!this.config.key_cache) {
		this.AES.clearKey();
		this.last_AES_page = "";
	} else
		this.last_AES_page = title;
	if (back) { // only if called from Lock:: page
		this.ui.back();
	} else {
		// need to refresh display; no history
		this.set_current(title, true, true);
	}
	// PVHL: moved because current page was saved as 'Lock::xxx'
	this.save_page_i(pi);
};

woas._perform_lock = function(pi) {
	// PVHL: Just a preventive; in case of a bug that could lock twice:
	//   only lock if unlocked
	if (!(page_attrs[pi] & 0x2)) {
		pages[pi] = this.AES.encrypt(pages[pi]);
		page_attrs[pi] |= 0x2;
	}
};

// auto-save thread
woas._auto_saver = function() {
	if (woas.save_queue.length && !woas.ui.edit_mode) {
		woas.commit(woas.save_queue);
		woas.menu_display("save", false);
	}
	// always clear previous thread
	clearTimeout(woas._autosave_thread);
	// re-launch the thread
	if (_this.config.auto_save)
		woas._autosave_thread = setTimeout("woas._auto_saver()", woas.config.auto_save);
};

woas._on_unload = function () {
	// close down Print & Help windows if they exist
	// Doesn't work in recent Opera
	if (this.popup_window && !this.popup_window.closed) {
		this.popup_window.close();
	}
	if (this.help_system.popup_window && !this.help_system.popup_window.closed) {
		this.help_system.popup_window.close();
	}
	// PVHL: These saves don't work; will leave code here for now. Testing
	//	 showed delayed save failures so delayed save was removed as an option
	//   (risky); config save was removed as it used to corrupt content; this
	//   (useless?) option actually saves the whole file currently IIRC.
	if (this.save_queue.length)
		this.commit(this.save_queue);
	else {
		if (this.config.save_on_quit && this.cfg_changed)
			this.cfg_commit();
	}
	return true;
};

// these are unchanged for all browsers
woas.getHTMLDiv = function(elem) {return elem.innerHTML;};
woas.setHTMLDiv = function(elem, html) {elem.innerHTML = html;};

// when the page is loaded - onload, on_load
woas._on_load = function() {
	// set up log functions so enable/disable does not require reload
	this._set_debug(this.config.debug_mode, this.config.debug_closed);
	d$("woas_debug_log").value = ""; // for Firefox
	// output platform information - note that revision is filled in only in releases
	woas.log("*** WoaS v"+this.version+"-pvhl-r2507"+" started");	// log:1
	// needed to check if data source changes; forces full save when entering/exiting
	// WSIF datasource mode or changing the name of the data source file
	this._old_wsif_ds = is_windows
		// convert unix path to windows path
		? this.config.wsif_ds.replace(reFwdSlash, '\\')
		: this.config.wsif_ds;

	// (0) set some browser-tied functions
	// PVHL: is the following warning still true? Take out of onload function
	// DO NOT use setHTML for the document.body object in IE browsers
	if (this.browser.ie && Number(this.browser.ie) < 9) {	// some hacks for IE
		this.setHTML = function(elem, html) {elem.text = html;};
		this.getHTML = function(elem) {return elem.text;};
	} else {
		this.setHTML = this.setHTMLDiv;
		this.getHTML = this.getHTMLDiv;
	}

	// (1) check integrity of WoaS features - only in debug mode
	if (this.log() && this.tweak.integrity_test && !this.integrity_test()) {
		// test failed, stop loading
		return;
	}

	// (2) load the actual pages (if necessary)
	if (this.config.wsif_ds.length) {
		// make sure file path is good for current browser
		var path = is_windows
			? this.config.wsif_ds.replace(reFwdSlash, '\\')
			: this.config.wsif_ds.replace(/\\/g, '/');
		if (!this._wsif_ds_load(path, this.config.wsif_ds_lock)) {
			// the file load error is already documented to user
			if (this.wsif.emsg !== null) {
				// force debug mode
				this._set_debug(true);
				this.crash("Could not load WSIF pages data!\n"+this.wsif.emsg);
			}
			return;
		}
	}

	// PVHL: if current doesn't exist can't continue; could have been done
	// earlier but this allows future enhancements (load default from wsif)
	if (!current) {
		// should modify to allow choice from among available pages;
		// this shouldn't be possible though - current should always be set
		this._set_debug(true);
		this.crash('No initial page setting found: can\'t continue!');
	}
	// (3) setup some DOM cage objects (read cache)
	this.dom.init();

	// (4) activate the CSS, with eventual fixups for some browsers
	this.css.set(this.get_text("WoaS::CSS::Core")+"\n"+this.get_text("WoaS::CSS::Custom"));

	// (5) continue with UI setup
	this.ui.img_display(); /* turn off images if data_uri doesn't work */
	d$('woas_home').title = this.config.main_page;
	this.ui.set_header(this.config.fixed_header);
	this.ui.set_menu(this.config.fixed_menu);

	// customized keyboard hook
	document.onkeydown = woas.ui._keyboard_event_hook;

	// (6) initialize extensions - plugins go first so that external javascript/CSS
	// starts loading
	this.setHTML(d$("woas_wait_text"), "Initializing extensions...");
	this.plugins.load();
	this._load_aliases(this.get_text("WoaS::Aliases"));
	this.hotkey.load(this.get_text("WoaS::Hotkeys"));

	// enable the auto-save thread
	if (this.config.cumulative_save && this.config.auto_save)
		this._autosave_thread = setTimeout("woas._auto_saver()", this.config.auto_save);

	this._editor = new TextAreaSelectionHelper(d$("woas_editor"));

	this.setHTML(d$("woas_wait_text"), "Completing load process...");

	// set a hook to be called when loading process is complete
	if (!woas.dom.wait_loading(woas._early_render))
		woas._load_hangup_check(true);
};

// the first page rendering is a delicate process
// plugins and related libraries/CSS must be loaded
// before rendering the first page to prevent some glitches
// to happen, like: missing CSS, missing macros etc
woas._dummy_fn = function() { return; };
woas._load_hangup_check = function(first) {
	// first time we just re-create the spawning thread
	if (!first) {
		if (!woas.dom._loading) {
			woas.log("_load_hangup_check() finished");
			return
		}
		// ask user if he wishes to continue waiting for libraries to finish loading
		if (!confirm(this.i18n.CONTINUE_WAIT_LOAD)) {
			// run the hook like if nothing hung up
			woas.dom._run_post_load_hook();
			woas.log("_load_hangup_check() cancelled");
			return;
		}
	}
	// launch again this thread, every 3s
	woas.log("_load_hangup_check() respawned (still loading: "+woas.dom.get_loading()+")");
	setTimeout("woas._load_hangup_check(false);", 3000);
};
	
// no 'this' for this function
// PVHL: should load document location here for later use as well
woas._early_render = function() {
	// PVHL: handle requested page in location: woas.html?page%20name#sect_name
	//   If page doesn't exist current is loaded instead.
	//   should add ability to give the href of pages and sections to user
	var loc = woas.trim(unescape(document.location.href.split('?')[1] || '')),
		page = loc.split('#')[0] || '',
		hash = document.location.href.split('#')[1],
		cr_bkup = current;
	hash = hash ? '#' + woas.parser.heading_anchor(unescape(hash), true) : ''; // see if IE needs null check
	if (!page || page_titles.indexOf(page) === -1) {
		// no such page;
		page = current;
	} else {
		cr_bkup = page;
	}
	// feed the current title before running the disable edit mode code
	woas.prev_title = cr_bkup;
	woas.disable_edit();
	// goto requested page or default (current; always exists by this point)
	// force go_to to load even if current
	current = '';
	woas.go_to(page + hash);
	current = cr_bkup;
//	this.progress_finish();
	woas.ui.display({wait: false});
	// launching post-load hook
	woas.post_load();
	// PVHL: awful hack may not be needed once scroll_wrap used
	//if (hash && woas.browser.webkit) {
	//	setTimeout('woas.go_to("'+hash+'")',0);
	//}
};

// disable edit-mode after cancel/save actions and on initial load
woas.disable_edit = function() {
//	woas.log("DISABLING edit mode");	// log:0
	// reset change buffer used to check for page changes
	this.ui.edit_mode = false;
	this.change_buffer = null;
	this.old_title = null;
	if (woas._ghost_page) {
		woas._ghost_page = false;
		woas.log("Ghost page disabled"); //log:1
	}
	this.ui.top();
	this.log(); // scroll to bottom of log
	this._set_title(this.prev_title);
	//woas.log(woas.history.log_entry()); //log:0
//if (console) console.log('disable edit: ' + this.history.log_entry());
};

function _lock_pages(arr) {
	this.alert(woas.i18n.NOT_YET_IMPLEMENTED);
}

function _unlock_pages(arr) {
	this.alert(woas.i18n.NOT_YET_IMPLEMENTED);
}

woas.edit_allowed = function(page) {
	// can always edit pages if they have an actual data representation
	if (this.tweak.edit_override)
		return (this.page_index(page) != -1);
	// force read-only
	if (!this.config.permit_edits)
		return false;
	if (this.edit_allowed_reserved(page))
		return true;
	// page in reserved namespace
	if (this.is_reserved(page))
		return false;
	// page has readonly bit set
	return !this.is_readonly(page);
};

woas.edit_allowed_reserved = function(page) {
	var _pfx = "WoaS::Plugins::";
	if (page.substr(0, _pfx.length) === _pfx)
		return true;
	// allow some reserved pages to be directly edited/saved
	switch (page) {
		case "WoaS::Aliases":
		case "WoaS::Hotkeys":
		case "WoaS::CSS::Custom":
			return true;
	}
	return false;
};

// setup the title boxes and gets ready to edit text
woas.current_editing = function(page, disabled, txt) {
//	woas.log("ENABLING edit mode");	// log:0
//	woas.log("current = \""+current+"\", current_editing(\""+page+"\", disabled: "+disabled+")");	// log:0
	_servm_alert();
	this.ui.edit_mode = true;
	this.prev_title = current;
	current = page;
	d$("wiki_page_title").disabled = (disabled && !this.tweak.edit_override ? "disabled" : "");
	d$("wiki_page_title").value = this.old_title = page;
	// save copy of text to check if anything was changed
	// do not store it in case of ghost pages
	d$("woas_editor").value = this.change_buffer = txt;
	this._set_title(this.i18n.EDITING.sprintf(page));
	woas.ui.display({view: false, edit: true}, true);
	d$("woas_editor").focus();
};

// PVHL: apparently removed - left here for now
woas.edit_ready = function (txt) {
	woas.log("Called woas.edit_ready!");	// log:1
	return;
}

woas.edit_page = function(page) {
	// can't edit again if already editing
	if (this.ui.edit_mode)
		return false;
	if (!this.edit_allowed(page)) {
		woas.log("Not allowed to edit page "+page);	// log:1
		return false;
	}
	var tmp = this.get_text(page);
	if (tmp===null) return false;
	if (this.is_embedded(page) && !this.is_image(page))
		tmp = this.base64.decode(tmp);
	// setup the wiki editor textbox
	this.current_editing(page, this.is_reserved(page), tmp);
	return true;
};

//API1.0: check if a title is valid
woas.valid_title = function(title) {
	if (title.length == 0) {
		this.alert(this.i18n.EMPTY_TITLE);
		return false;
	}
	if (title.length > 256) {
		this.alert(this.i18n.TOO_LONG_TITLE.sprintf(256));
		return false;
	}
	if (title.match(/(\[|\]|\{|\}|\<|\>|\||\#|\"|:::)/)) {
		this.alert(this.i18n.INVALID_TITLE);
		return false;
	}
	if (title.substr(-2)==="::") {
		this.alert(this.i18n.ERR_PAGE_NS);
		return false;
	}
	var ns = this.get_namespace(title, true);
	if (ns.length && this.is_reserved(ns+"::") && !this.tweak.edit_override) {
		this.alert(this.i18n.ERR_RESERVED_NS.sprintf(ns));
		return false;
	}
	return true;
};

woas.rename_page = function(previous, newpage) {
	woas.log("Renaming "+previous+" to "+newpage);	// log:1
	if (this.page_index(newpage)!=-1) {
		this.alert(this.i18n.PAGE_EXISTS.sprintf(newpage));
		return false;
	}
	// this is the actual rename operation
	var pi = this.page_index(previous);
	page_titles[pi] = newpage;
	// variables used to change all occurrencies of previous title to new title
	var reTitles = new RegExp("\\[\\[(Include::)?" + RegExp.escape(previous) + "(\\]\\]|\\|)", "g"),
		// the original page (dried)
		P = {body:null},
		// the expanded
		NP = {body:null},
		changed,
		snippets,
		ilen;
	for(var i=0,l=pages.length;i < l;i++) {
		P.body = this.get_page(i);
		if (P.body === null)
			continue;
		changed = false;
		snippets = [];
		// dry removes nowiki/macros/comments, but without dynamic newlines
		this.parser.dry(P, NP, snippets);
		// replace direct links and transclusion links
		NP.body = NP.body.replace(reTitles, function (str, inc) {
			changed = true;
			inc = inc || '';
			ilen = 2 + inc.length;
			return str.substr(0, ilen)+newpage+str.substr(previous.length+ilen);
		});
		if (changed) {
			this.parser.undry(NP, snippets);
			this.set__text(i, NP.body);
		}
		P.body = NP.body = snippets = null;
	}
	if (previous === this.config.main_page)
		this.config.main_page = newpage;
	// make sure that previous title is consistent
	if (this.prev_title === previous)
		this.prev_title = newpage;
	this.history.rename(previous, newpage);
	return true;
};

woas.get_raw_content = function() {
	var c = d$("woas_editor").value;
 	// remove CR added by some browsers
 	//TODO: check if ie8 still adds these
	// PVHL: ie8 does, ie9 doesn't; changed so it doesn't matter
	// though a fixed Opera will take longer ... insignificant,
	// and I will change in new version (function as found didn't work anyway)
	if (((this.browser.ie && this.browser.ie < 9) || this.browser.opera) && /\r\n/.test(c)) {
		c = c.replace(/\r\n/g, "\n");
	}
 	return c;
};

// action performed when save is clicked
woas.save = function() {
	if (!this.ui.edit_mode) {
		if (this.config.cumulative_save) {
			// when this function is called in non-edit mode we perform
			// a full commit for cumulative save
			this.full_commit(); // PVHL: this could have failed!
			this.menu_display("save", false);
			return;
		} else {
			// you can't save if not editing
			return false;
		}
	}
	var raw_content = this.get_raw_content(),
		do_save = this._ghost_page || (raw_content !== this.change_buffer),
		back_to = this.prev_title,
		can_be_empty = false,
		skip = false,
		renaming = false,
		menu = false;

	switch(current) {
	case "WoaS::CSS::Custom":
		if (do_save) {
			this.css.set(this.get_text("WoaS::CSS::Core")+"\n"+raw_content);
			this.pager.set_body(current, raw_content);
		}
		break;
	case "WoaS::Aliases":
		if (do_save)
			this._load_aliases(raw_content);
		can_be_empty = true;
		skip = true;
		// fallthrough wanted
	case "WoaS::Hotkeys":
		if (!skip && do_save)
			this.hotkey.load(raw_content);
		// fallthrough wanted
	default:
		// check if text is empty (page deletion)
		if (do_save && (raw_content === "") && !can_be_empty) {
			if (this._ghost_page) {
				this.ui.cancel();
			} else if (confirm(this.i18n.CONFIRM_DELETE.sprintf(current))) {
				this.plugins.delete_check(current);
				this.delete_page(current);
				this.prev_title = current;
				this.disable_edit();
			}
			return;
		} else {
			var new_title = this.trim(d$("wiki_page_title").value);
			renaming = (this.old_title !== new_title);
			do_save |= renaming;
			if (this._ghost_page) {
				// new page needs history
				this.history.store(this.prev_title);
				this.prev_title = new_title;
			}
			if (do_save) {
				// rename if title is valid
				if (renaming && (
						!this.valid_title(new_title) ||
						!this.rename_page(this.old_title, new_title))) {
					return false;
				}
				// actually set text only if it was changed
				if (do_save)
					this.pager.set_body(new_title, raw_content);
				var menu = this.is_menu(new_title);
				// update the plugin if this was a plugin page
				// NOTE: plugins are not allowed to be renamed, so
				// old title is equal to new title
				if (!menu) {
					back_to = new_title;
					var _pfx = "WoaS::Plugins::";
					if (new_title.substr(0, _pfx.length) === _pfx) {
						// we do not directly call _update_plugin because
						// plugin does not exist before creation so disabling it
						// would fail
						this.plugins.disable(new_title.substr(_pfx.length));
						this.plugins.enable(new_title.substr(_pfx.length));
					}
				}
			}
		}
	}
	if (do_save) {
		this.save_page(current);
	}
	this.set_current(back_to, true, true); // don't clear fwd history
	this.disable_edit();
};

woas.save_page = function(title) {
	return this.save_page_i(this.page_index(title));
};

woas.save_page_i = function(pi) {
	// update the modified time timestamp (only when not in dev-mode)
	if (!this.tweak.edit_override)
		page_mts[pi] = this.config.store_mts ? Math.round(new Date().getTime()/1000) : 0;
	// this is the dummy function that will allow more efficient file saving in future
	if (this.config.cumulative_save) {
		// add the page to the bucket, if it isn't already in
		if (!this.save_queue.length) {
			this.save_queue.push(pi);
			this.menu_display("save", true);
		} else {
			if (this.save_queue.indexOf(pi)==-1)
				this.save_queue.push(pi);
		}
		woas.log("save_queue = ("+this.save_queue+")");	// log:1
		return true;
	}
	return this.commit([pi]);
};

woas.create_breadcrumb = function(title) {
	if (title === "::Menu") {
		return title;
	} else if (title.indexOf('Javascript::') === 0) {
		return 'Javascript :: ' + title.substr(12);
	}
	var tmp = title.split("::");
	if (tmp.length === 1)
		return title;
	var s = "", partial = "", js = "", i, il;
	for(i = 0 , il = tmp.length - 1; i < il; i++) {
		// editing is active - PVHL: not used any more?
		if (this.ui.edit_mode)
			s += tmp[i]+" :: ";
		else {
			partial += tmp[i]+"::";
			js = "woas.go_to('"+this.js_encode(partial)+"')";
			// add link to "::" if it isn't on the end of the title
			s += tmp[i] + (tmp[i + 1] ? " <"+"a class=\"woas_link\" title=\"" +
				this.xhtml_encode(partial)+"\" onclick=\"" + js +
				"; return false;\">::<"+"/a> " : " ::");
		}
	}
	// add page title
	return s + tmp[tmp.length-1];
};

/*** src/extensions.js ***/
// @module scripting
// @description manages custom scripts declared in menu and main page
// All custom scripts can be defined in one of the two
woas.scripting = {
	menu: [],	// scripts active in menu
	page: [],	// scripts active in page
	_menu_stacked: 0,	// number of elements which shall be cleared
	_page_stacked: 0,	// ''

	// remove all scripts from specified array (can be 'menu' or 'page')
/*
PVHL:
  scripting needs to be rethought; Javascript tags can be removed from the DOM
  without affecting the code that the tag initialized; it survives. Would need
  to have all scripts added to a namespace closure so that the namespace could
  be cleared. Facebook does something like this, as does adSafe, I believe,
  but it is not a trivial implementation task.
*/
	clear: function(which) {
		for(var i=0;i < this["_"+which+"_stacked"];++i) {
			woas.dom.remove_script(which, i);
		}
		this["_"+which+"_stacked"] = 0;
	},

	// add a custom script for later activation
	add: function(which, content, external) {
		this[which].push([content, external]);
	},

	activate: function(which) {
		for(var i=0;i < this[which].length;++i) {
			if (woas.dom.add_script(which, i, this[which][i][0], this[which][i][1]))
				++this["_"+which+"_stacked"];
		}
		// free memory
		this[which] = [];
	},

	remove: function(which, index) {
		if (woas.dom.remove_script(which, index)) {
			--this["_"+which+"_stacked"];
			return true;
		}
		return false;
	}

};

// @module 'plugins'
woas.plugins = {

	// flag set by last call to get()
	is_external: false,
	_all: [],
	_active: [],	// list of enabled plugins

	get: function(name) {
		this.is_external = false;
		var text = woas.pager.get("WoaS::Plugins::"+name);
		// check if this is an external page reference
		if (name.charAt(0) === '@') {
			// hack for external files loading at run-time
			// each source file specified in a new line as a definition with flags for different browsers
			var uris = this._parse_external(text);
			if (uris !== null) {
				// we got it
				this.is_external = true;
				text = uris;
			}
		}
		return text;
	},

	_parse_external: function(text) {
		var uris=[], uri_def, p, sb;
		text = text.split("\n");
		for(var i=0;i < text.length;++i) {
			uri_def = woas.trim(text[i]);
			if (!uri_def.length)
				continue;
			// check this URI for validity
			p = uri_def.indexOf("=");
			if (p === -1)
				continue;
			sb = this._craft_object(uri_def.substr(p+1));
			if (sb === null) // no mode was activated by this definition
				continue;
			sb.src = woas.trim(uri_def.substr(0,p));
//			woas.log(sb.src+" " +sb.is_inline+" "+sb.is_async);
			// finally add it to basket
			uris.push(sb);
		}
		if (uris.length == 0)
			woas.log("no valid source URIs found");
		return uris;
	},

	reIncludeDef: new RegExp("([\\+@])(\\*|([a-zA-Z0-9_]+)(\\([0-9\\.]+[-\\+]?\\))?)", "g"),

	// parse definitions for browser include type
	_craft_object: function(s) {
		var sb = {
			is_inline: false,
			is_async: false
		}, inline_init = false, async_init = false;
		s.replace(this.reIncludeDef, function(str, sym, full_browser_str,browser_str, version) {
			// a handy shortcut
			switch (browser_str) {
				case "ff":
					browser_str = "firefox";
				break;
				// not supported
				case "ie6": case "ie8": case "firefox2": case "firefox3": case "firefox_new":
					woas.log("Invalid browser token: "+browser_str);
					return;
			}
			// check the catch-all case
			if (full_browser_str === '*') {
				if (sym === '+') {
					if (!inline_init) {
						inline_init = sb.is_inline = true;
					} else woas.log("Ignored catch-all inline because a restricting criteria was already specified");
				} else { // if (sym === '@')
					if (!async_init) {
						async_init = sb.is_async = true;
					} else woas.log("Ignored catch-all async because a restricting criteria was already specified");
				}
				return;
			}
			// check that this browser token is valid
			var t = typeof woas.browser[browser_str];
			if (t == "undefined") {
				woas.log("Invalid browser token: "+browser_str);
				return;
			}
			// parse the symbol if that browser token is active and version matches
			if (woas.browser[browser_str]) {
				// make a version check only if necessary
				var its_ok = false;
				if (version.length !== 0) {
					// check that we have a version string, before all
					if (t != "string") {
						woas.log("No version string for browser token \""+browser_str+"\"");
						return;
					}
					// remove parenthesis
					version = version.substr(1, version.length-2);
					// check the last character
					var lc = version.charAt(version.length-1);
					if (lc === '+') { // match version and above
						its_ok = (woas.strnatcmp(woas.browser[browser_str], version) >= 0);
					} else if (lc === '-') { // match version and below
						its_ok = (woas.strnatcmp(woas.browser[browser_str], version) <= 0);
					} else { // plain version match
						its_ok = (woas.strnatcmp(woas.browser[browser_str], version) == 0);
					}
				} else its_ok = true;
				// version was not OK
				if (!its_ok) return;
				// operate the operator
				if (sym === '+') {
					sb.is_inline = true;
					sb.is_async = false;
					inline_init = true;
				} else {
					sb.is_async = true;
					sb.is_inline = false;
					async_init = true;
				}
			}
			// continue with next token
		});
		// if nothing was specified, fail
		if (!inline_init && !async_init) return null;
		return sb;
	},

	// disable one single plugin
	disable: function(name) {
		var i = this._active.indexOf(name);
		if (i !== -1) {
			_mapped_name = this._mapping(name);
			// attempt removing the script block and fail otherwise
			if (!woas.dom.remove("plugin", _mapped_name))
				return false;
			// external plugin, try to remove the lib blocks created
			if (name.charAt(0) === '@') {
				var p = this.get(name);
				if (this.is_external && (p.length>1)) { // *special* external plugins
					for(var i=0;i < p.length;++i) {
						woas.dom.remove_script("lib", _mapped_name+'_'+i);
					}
				}
			}
			this._active.splice(i, 1);
			return true;
		}
		return false;
	},

	update: function(name) {
		return this.disable(name) && this.enable(name);
	},

	_internal_add: function(name, s) {
		if (s.is_async) {
			if (woas.dom.add_script("plugin", this._mapping(name), s.src, true)) {
				this._active.push( name );
				return true;
			}
		} else /*if (s.is_inline) */ { // create an inline javascript (slower)
			var ct = woas.load_file(woas.ROOT_DIRECTORY+woas.fix_path_separators(s.src)),
				t = (typeof ct);
			// write some nice message
			if (t.toLowerCase() != "string") {
				woas.log("could not load inline javascript source "+s.src);
				return false;
			} else {
				// add the inline block
				if (woas.dom.add_script("plugin", this._mapping(name), ct, false)) {
					this._active.push( name );
					return true;
				}
			}
		}
		// failed adding DOM script
		return false;
	},

	// enable a single plugin
	enable: function(name) {
		if (this._active.indexOf(name) !== -1) {
			woas.log("BUG: Plugin "+name+" is already active");
			return true;
		}
		// generate the script element
		var p = this.get(name);
		if (this.is_external) { // *special* external plugins
			// single reference, do not create script block
			if (p.length === 1) {
				return this._internal_add(name, p[0] );
			} else {
				var js="";
				for(var i=0;i < p.length;++i) {
					if (p[i].is_async)
						js += 'woas.dom.add_script("lib", "'+this._mapping(name)+'_'+i+"\", \""+woas.js_encode(p[i].src)+"\", true);\n";
					else /*if (p[i].is_inline) */ {
						var ct = woas.load_file(woas.ROOT_DIRECTORY+woas.fix_path_separators(p[i].src)),
							t = (typeof ct);
						// write some nice message
						if (t.toLowerCase() !== "string")
							js += "/* woas.load_file(\"::/"+p[i].src+"\") returned "+ct+" ("+t+") */\n";
						else {
							// add the loaded code
							js += ct; ct = null;
						}
					} // no other symbols for now
				} //efor
				// finally add the real script block
				if (woas.dom.add_script("plugin", this._mapping(name), js, false)) {
					this._active.push( name );
					return true;
				}
				return false;
			}
		}
		// normal plugins
		if (woas.dom.add_script("plugin", this._mapping(name),
					p, false)) {
			this._active.push( name );
			return true;
		}
		return false;
	},

	// remove DOM object for all active plugins
	clear: function() {
		for(var i=0,it=this._active.length;i < it;++i) {
			// remove the DOM object
			this.dom.remove_script("plugin", this._mapping(this._active[i]));
		}
		// reset array
		this._active = [];
		this._all = [];
	},

	// map a plugin name to an unique name
	_mapping_cache:[],
	_mapping: function(name) {
		var i = this._mapping_cache.indexOf(name);
		if (i == -1) {
			i = this._mapping_cache.length;
			this._mapping_cache.push(name);
		}
		// return more descriptive names
		if (woas.config.debug_mode)
			return woas._unix_normalize(name).replace("@", '')+"_"+i;
		return i;
	},

	load: function() {
		//TODO: get plugins configuration

		// get list of plugins
		var _pfx = "WoaS::Plugins::", l=_pfx.length, name;
		for(var i=0,it=page_titles.length;i < it;++i) {
			if (page_titles[i].substr(0, l) === _pfx) {
				name = page_titles[i].substr(_pfx.length);
				// generate the script element
				this.enable(name);
				this._all.push(name);
			}
		} //efor
	},

	list: function() {
		var pt = this._all.length;
		if (pt === 0)
			return "\n\n/No plugins installed/";
		var pg=[];
		for(var i=0;i < pt;++i){
			pg.push("* [[WoaS::Plugins::"+this._all[i]+"|"+this._all[i]+"]]"+
					//TODO: some CSS for the plugin actions
					"&nbsp;&nbsp;[[Javascript::woas.plugins.remove('"+this._all[i]+"')|Delete]]"+
					"&nbsp;&nbsp;[[Javascript::woas._edit_plugin('"+this._all[i]+"')|Edit...]]"+
					"\n");
		}
		return "\n\n"+woas._simple_join_list(pg);
	},

	describe_external: function(uris) {
		// show a list of external sources
		var ntext = "<"+"p>This plugin is made up of the following external sources:<"+"/p><"+"ul>", uri;
		for(var i=0;i < uris.length;++i) {
			ntext += "<"+"li>" + "<"+"big>"+(uris[i].is_inline ? "(inline)" : "(external)")+"<"+"/big>&nbsp;";
			ntext += "<"+"a href=\""+uris[i].src+"\" target=\"_blank\">"+uris[i].src+"<"+"/a><"+"/li>\n";
		}
		return ntext+"<"+"/ul>";
	},

	// if given page name is a plugin, disable it
	// used when deleting pages
	delete_check: function(pname) {
		var _pfx = "WoaS::Plugins::";
		if (pname.substr(0, _pfx.length) === _pfx)
			this.disable(pname.substr(_pfx.length));
	},

	remove: function(name) {
		var page_name = "WoaS::Plugins::"+name;
		if (!confirm(woas.i18n.CONFIRM_DELETE.sprintf(page_name)))
			return false;
		// first we attempt to disable it, ignoring failure (because it could just not be active)
		this.disable(name);
		woas.delete_page(page_name);
		// remove from array
		var i = this._all.indexOf(name);
		this._all.splice(i,1);
		if (current === "WoaS::Plugins") {
			//HACK: reload plugins
			woas.setHTMLDiv(d$("woas_page"), woas.parser.parse(woas.get_text("WoaS::Plugins") + this.list()));
		}
		return true;
	}

};

// @module hotkey
woas.hotkey = {

	all: {
		"save":		"s",
		"edit":		"e",
		"print":	"p",
		"help":		"h",
		"goto":		"g",
		"cancel":	0x1b,
		"back":		0x8
	},
	cached_default: null,
	custom_accesskeys: [],

	_update_accesskeys: function(new_custom_accesskeys) {
		var ak, a, b, at, bt;
		// we store the length of old access keys before looping because
		// other entries might be added during the cycles
		bt=this.custom_accesskeys.length;
		for(a=0,at=new_custom_accesskeys.length;a < at;++a) {
			found = false;
			for (b=0;b < bt;++b) {
				// access key already exists
				if (this.custom_accesskeys[b].key === new_custom_accesskeys[a].key) {
					found = true;
					break;
				}
			}
			// proceed to addition
			if (!found) {
				ak = document.createElement("a");
				this._hook_fn(ak, new_custom_accesskeys[a].fn);
				ak.accessKey = new_custom_accesskeys[a].key;
				// store the new access key
				this.custom_accesskeys.push({"fn":new_custom_accesskeys[a].fn,"key":new_custom_accesskeys[a].key,
											 "obj":ak});
				d$("woas_custom_accesskeys").appendChild(ak);
			}
		}
		// (3) clear the div content if no custom access key is there (just for safety)
		if (this.custom_accesskeys.length === 0)
			this.setHTML(d$("woas_custom_accesskeys"), "&nbsp;");
	},

	_hook_fn: function(obj, fn) {
		woas.log("setting onclick for "+fn);
		if (woas.browser.gecko || woas.browser.webkit)
			obj.setAttribute("onclick", fn+"()");
		else //HACK
			obj.onclick = eval(fn);
	},

	// return the default hotkeys/key bindings
	_cache_default: function() {
		if (this.cached_default === null) {
			this.cached_default="";
			var k;
			for(var hkey in this.all) {
				k = this.all[hkey];
				switch(typeof k) {
					case "string":
					break;
					default: // Number
						k = "0x"+k.toString(16);
				}
				this.cached_default += "$"+hkey.toUpperCase()+"\t"+k+"\n";
			}
		}
		return this.cached_default;
	},

	validate: function(k) {
		// validate hexadecimal hotkey
		if (k.substr(0, 2) == "0x") {
			k = parseInt(k.substr(2), 16);
			if (!k)
				return null;
			return k;
		}
		// validate single ASCII character
		if (k.length>1)
			return null;
		return k;
	},

	load: function(s) {
		var new_custom_accesskeys=[];
		// identify valid alias lines and get the key binding/hotkey
		s.replace(this.reHotkeys, function(str, hkey, lambda, binding) {
			// check that binding is a valid key
			binding = woas.hotkey.validate(binding);
			if (binding === null) {
				woas.log("Skipping invalid key binding for hotkey "+hkey);	//log:1
				return;
			}
			// associate a custom key binding
			if (hkey === "CUSTOM") {
				// store the custom definition for later update
				lambda = lambda.substr(1, lambda.length-2);
				new_custom_accesskeys.push({"fn":lambda, "key":binding});
			} else {
				// convert hotkey to lowercase
				hkey = hkey.toLowerCase();
				// check that hotkey exists
				if (typeof woas.hotkey.all[hkey] == "undefined") {
					woas.log("Skipping unknown hotkey "+hkey);	//log:1
					return;
				}
				// associate hotkey and key binding
				woas.hotkey.all[hkey] = binding;
			}
		});
		// once finished loading hotkey definitions, associate them
		d$("woas_save").accessKey = this.all.save;
		d$("woas_edit").accessKey = this.all.edit;
		d$("woas_print").accessKey = this.all.print;
		d$("woas_help").accessKey = this.all.help;
		// set access key for goto feature
		new_custom_accesskeys.push({fn:"woas.cmd_go_to", key: this.all["goto"]});

		// (1) delete access keys which no more exist
		var found,a,b;
		for(a=0,at=this.custom_accesskeys.length;a < at;++a) {
			found = false;
			for (b=0,bt=new_custom_accesskeys.length;b < bt;++b) {
				if (this.custom_accesskeys[a].key === new_custom_accesskeys[b].key) {
					found = true;
					// access key element was found, update the associated function (if necessary)
					if (this.custom_accesskeys[a].fn !== new_custom_accesskeys[b].fn) {
						this._hook_fn(this.custom_accesskeys[a].obj, new_custom_accesskeys[b].fn);
					}
					break;
				}
			}
			// proceed to removal
			if (!found) {
				d$("woas_custom_accesskeys").removeChild(this.custom_accesskeys[a].obj);
				delete this.custom_accesskeys[a].obj;
				this.custom_accesskeys.splice(a,1);
				--at;
			}
		}
		// (2) add new access keys
		this._update_accesskeys(new_custom_accesskeys);
	},

	reHotkeys: /^\$([A-Za-z0-9_]{2,})(\([A-Za-z0-9_]+\))?\s+([\S]+)\s*$/gm
};

// call once during code setup to store the current default hotkeys
woas.hotkey._cache_default();

woas._edit_plugin = function(name) {
	if (this.go_to("WoaS::Plugins::"+name))
		woas.edit_page(current);
};

var reAliases = /^(\$[A-Za-z0-9_]{2,})\s+(.*?)$/gm;
// match all aliases defined in a page
woas._load_aliases = function(s) {
	this.aliases = [];
	if (s==null || !s.length) return;
	s.replace(reAliases, function(str, alias, value) {
		// save the array with the alias regex and alias value
		var cpok = [ new RegExp(RegExp.escape(alias), "g"), value];
		woas.aliases.push(cpok);
	});
};

woas.aliases = [];

woas.title_unalias = function(aliased_title) {
	// apply aliases on title, from newest to oldest
	for(var i=0,l=this.aliases.length;i < l;++i) {
		aliased_title = aliased_title.replace(this.aliases[i][0], this.aliases[i][1]);
	}
	return aliased_title;
};

woas.macro = {
	// macro definition regex
	// Follows nowiki block rules. If line after tag contains only whitespace it is removed,
	// as is the last \n (so text is just what appears between the tags). Also allows an
	// optional single space after colon if text is on the same line as opening tag.
	// 1: name, 2: params, 3: newline before text, 4: text without last newline
	reMacroDef: /^(%?[A-Za-z0-9_\.]+)\s*(\(.*?\))?\s*: ?(?:[ \t]*(\n))?([\s\S]*?)(?:\n[ \t]*)?$/,

	// macro syntax plugin code adapted from FBNil's implementation
	parser: function(text){
		// standard macro object
		var macro = { "reprocess": false, "text": text, parse: this._parse };
		// match macro definition/call
		var M = text.match(this.reMacroDef);
//woas.log("0: '"+M[0]+"'\n1: '"+M[1]+"'\n2: '"+M[2]+"'\n3: '"+M[3]+"'\n4: '"+M[4]+"'")
		// if no colon declaration was found, then do not process anything
		if (M !== null) {
			var fn = M[1];
			// check validity of macro name
			if ((fn.indexOf("..") !== -1) || (fn.charAt(0) === '.') ||
				(fn.charAt(fn.length-1) === '.')) {
					woas.log("Invalid macro name: " + fn);	//log:1
					return macro;
			}
			// check if this is a macro definition request
			if (fn.charAt(0) === '%') {
				fn = fn.substr(1);
				// when macro is not defined, define it
				if (this.create(fn, M[2], M[4])) {
					// we totally remove the block
					macro.text = "";
		//			macro.text = "<!-- defined "+fn+" macro -->";
				} else { // set some error message
					macro.text = woas.parser._make_preformatted(M[0], "color:#f00;font-weight:bold");
				}
				macro.block = true;
				macro.defn = true;
				return macro;
			}
			var fi = this.names.indexOf(fn);
			if (fi !== -1) {
				macro.text = M[4];
				// if we have no parameters, direct call function
				var pl, rv;
				if (typeof M[2] == "undefined") { pl = 0; }
				else { pl = M[2].length; }
				try {
					if (pl === 0) {
						rv = this.functions[fi](macro);
					} else {
						// inline insertion of parameters
						// cannot use woas.eval because we need context for 'macro'
						rv = eval( "(woas.macro.functions[" + fi + "])" +
									"(macro," + M[2].substr(1, pl-2) + ");" );
					}
				} catch(e) {
					woas.log("Error during macro execution: "+e);
				}
				// analyze return value
				if (rv === false) {
					// when macro returns false we automatically highlight it
					macro.reprocess = false;
					macro.text = woas.parser._make_preformatted(text, "color:#f00;font-weight:bold");
				} else {
					if (M[3] && macro.reprocess) {
						// allows block level syntax to be used (headings, lists, etc.)
						macro.text = woas.parser.NL_MARKER + '\n' + macro.text;
					}
					if (typeof rv === "undefined") {
						woas.log("WARNING: " + this.names[fi] + " did not return any value");
					}
				}
			} else {
				woas.log("Undefined macro " + fn);	//log:1
				macro.text = woas.parser._make_preformatted(text, "color:#f00");
			}
		} else { // bad macro name definition (e.g. '<') can wipe out other text; mark it
			woas.log("Macro failed validity test: '" + text + "'");	//log:1
			macro.text = woas.parser._make_preformatted(text, "color:#f00");
		}
//woas.log("'"+macro.text+"'")
		return macro;
	},

	// this is the function to be called to register a  macro
	// each macro function must accept a macro object as parameter and modify
	// such object (it is always passed by reference)
	register: function(fn_name, fn_object) {
		if (this.names.indexOf(fn_name) != -1) {
			woas.log("cannot redefine macro "+fn_name); //log:1
			return false;
		}
		this.names.push(fn_name);
		this.functions.push(fn_object);
		return true;
	},

	// some default macros
	default_macros: {
		// advanced transclusion: each newline creates a parameter
		include : function(m) {
			var params = m.text.split("\n"), nt, paramno, trans;
			// embedded transclusion not supported
			if (!params.length || !woas.page_exists(params[0]) || woas.is_embedded(params[0]))
				return false;
			// PVHL: allow control for page listings, even if we are deeply transcluded
			trans = woas.parser._transcluding;
			woas.parser._transcluding = 0;
			nt = woas.get_text_special(params[0]);
			woas.parser._transcluding = trans;
			if (nt === null)
				return false;
			if (params.length) { // replace transclusion parameters
				nt = nt.replace(/%\d+/g, function(str) {
					paramno = parseInt(str.substr(1));
					if (paramno < params.length)
						return params[paramno];
					else
						return str;
					} );
			}
			m.text = nt;
			m.reprocess = true;
			return true;
		},
		// PVHL: this is mostly to make the Help note more flexible, but...
		//   why not pass in the type and make it text box - or add such; so:
		//   woas.box(note): blah.... <<.box(alert) hi>> (I want this '.'
		// 	 form for official, and to drop the ':' after - unneeded; or maybe
		//   use '::' as for system pages: e.g. ::box(info) my text...)
		//   <<.box blah ...>> would give the default box -- note probably.
		//   All this need do is change the class through a switch; all done in CSS.
		//   Or don't use a switch and rely on user -- any can be added then.
		note: function(m) {
			// the extra div helps IE6
			var txt1 = "<"+"div><"+"div class='woas_note'>"+woas.i18n.NOTE_TEXT+" ",
				txt2 = "</"+"div><"+"/div>";
			m.text = txt1 + m.text + txt2;
			m.reprocess = true;
			m.block = true;
			return true;
		}
	},

	// the name of macros as they are called from wiki text
	names: [],
	// the actual function objects being called
	functions: [],

	// a reduced charset for javascript argument names
	reFindArgDef: /([a-z0-9_]+)\s*,/gi,
	reFindArgDefLast: /([a-z0-9_]+)\s*$/gi,
	create: function(fn_name, fn_params, fn_code) {
		// duplicated from register function
		if (this.names.indexOf(fn_name) != -1) {
			woas.log("cannot redefine macro "+fn_name); //log:1
			return false;
		}
		// prepare for passing other params
		// parameter definitions can be very limited in charset
		var real_params=[], other_params = "";
		if (((typeof fn_params).toLowerCase() == "string") && fn_params.length) {
			// remove parenthesis
			fn_params = fn_params.substr(1, fn_params.length-2);
			this.reFindArgDef.lastIndex = 0;
			fn_params.replace(this.reFindArgDef, function(str, pname) {
				real_params.push(pname);
			});

			this.reFindArgDefLast.lastIndex = this.reFindArgDef.lastIndex;
			fn_params.replace(this.reFindArgDefLast, function(str, pname) {
				real_params.push(pname);
			});
		}

		if (real_params.length)
			other_params = ","+real_params.join(",");
		else other_params = "";
		var obj = woas.eval("function (macro"+other_params+") {\n"+fn_code+"\n}", true);
		if (woas.eval_failed) {
			woas.log("cannot define function "+fn_name+": "+woas.eval_fail_msg); //log:1
			return false;
		}
		return this.register(fn_name, obj);
	},

	// code used to save backups of macro definitions
	// called by parser
	_backup: [],
	make_backup: function() {
		if (this._backup.length) {
			woas.log("BUG: macro.make_backup called when backup already exists");
		} else {
			this._backup.push(this.names.slice(0));
			this._backup.push(this.functions.slice(0));
		}
	},

	remove_backup: function() {
		if (this._backup.length) {
			this.functions = this._backup.pop();
			this.names = this._backup.pop();
		} else {
			woas.log("BUG:  macro.remove_backup called when no backup exists");
		}
	},

	// not used but left as possibly useful for testing
	has_backup: function() {
		return (this._backup.length !== 0);
	}

}; // end of woas.macro module

// some initialization
woas.macro.names.push("woas.include");
woas.macro.functions.push(woas.macro.default_macros.include);
woas.macro.names.push("woas.note");
woas.macro.functions.push(woas.macro.default_macros.note);

/*** src/datalayer.js ***/
/*
 *  API for the data layer abstraction
*/

// @module lock
// provides locking facilities by using a file describing locked entries
woas.lock = {
	// hashmap with a lock entry for each active filename
	datasources : {},
	
	_reset : function() {
		// clear object
		this.datasources = {};
		//TODO: add one entry for each expected datasource
	},
	
	_generate_magic_lock : function() {
		return _random_string(10);
	},
	
	_load_locks : function() {
		// locking currently disabled
		return true;
/*		var lck_file = woas.ROOT_DIRECTORY + woas.config.wsif_ds + ".lock";
		// attempt reading the lock file index
		var lock_data = woas.load_file(lck_file);
		// fail in case of no loading API available
		if (lock_data === null)
			return false;
		var need_save = false;
		// the lock file does not exist, it's time to initialize it
		if (lock_data === false) {
			this._reset();
			// we will write the file
			need_save = true;
		} else {
			// check that
		}
		return true;
*/
	},
	
	_update_locks : function() {
		//TODO: write the lock file index
		return true;
	},
	
	is_locked : function(filename) {
		// if lock is not defined, it is not active of course
		if (typeof this.datasources[filename] == "undefined")
			return false;
		return this.datasources[filename].active;
	},
	
	// called when editing some page which modifies one or more datasources
	// returns true if lock could be held successfully
	hold : function(filename, whom) {
		// locking currently disabled
		return true;
/*		// (1) each time there is an attempt to lock/unlock something we read the lock file index
		// and check if the datasource has been locked or if there have been changes to some lock
		if (!this._load_locks())
			return false;
		
		// (2) is this file already locked?
		if (this.is_locked(filename)) {
			var lock = this.datasources[filename];
			if (!confirm("%s was locked by %s at %s.\nDo you want to ignore this lock?\n\nWARNING: PRESS OK ONLY IF NOBODY ELSE IS EDITING".
						sprintf(filename, lock.owner, lock.when.toLocaleString()
						)))
				return false;
			// otherwise ignore lock
			lock = null;
		}
		
		// (3) re-create the lock
		this.datasources[filename] = {
			magic : this._generate_magic_lock(),		// magic is used to compare two locks
			owner : whom,								// author of locking
			when : new Date(),							// when locking happened
			active : true
		};
		
		// update the lock index
		return this._update_locks();
*/
	},
	
	release : function(filename) {
		// locking currently disabled
		return true;
/*		// (1) each time there is an attempt to lock/unlock something we read the lock file index
		// and check if the datasource has been locked or if there have been changes to some lock
		if (!this._load_locks())
			return false;
		// (2) check if datasource is actually locked
		if (typeof this.datasources[filename] == "undefined") {
//			woas.log("BUG: NO LOCK exists for "+filename);	//log:0
			return false;
		}
		// unactive the lock object (but keep it to check if file was modified)
		this.datasources[filename].active = false;
		// update the lock index
		return this._update_locks();
*/
	}
};

/*
PVHL: returns 0 if save failed, -1 if path not specified;
blob save disabled until it works cross-browser; at that time inline_wsif needs
to be passed into this function - was always set for multi-file wsif.
*/
woas._wsif_ds_save = function(subpath, ds_lock, plist) {
	// if we have a native sub-path, trigger the WSIF datasource save
	if (subpath.length === 0)
		return -1; // this will test true (no error)
	// always save in the root directory or a path below it
/**
PVHL: the option page has always stated that a relative path can be entered
for the WSIF data source -- as the argument 'subpath' suggests -- so we can't
just save to rootdirectory. The original code saved the index file to the
subpath, and multiple-WSIF files to the root!
*/
	var fname, pos;
	// wsif_ds is stored in UNIX format, but just in case
	subpath = subpath.replace(/\\/g, '/');
	pos = subpath.lastIndexOf('/') + 1;
	if (pos) {
		fname = subpath.substring(pos);
		subpath = woas.ROOT_DIRECTORY + subpath.substring(0, pos);
	}  else {
		fname = subpath;
		subpath  = woas.ROOT_DIRECTORY;
	}
	if (is_windows) {
		// convert unix path to windows path
		subpath = subpath.replace(reFwdSlash, '\\');
	}
	return this._native_wsif_save(subpath, fname, this.config.wsif_ds_lock,
							!this.ui.wsif_ds_multi,	true,
							this.config.wsif_author, true, plist);
};

//API1.0: save all pages
woas.full_commit = function() {
	var r = this._wsif_ds_save(this.config.wsif_ds, this.config.wsif_ds_lock, []);
	// PVHL: don't save html if wsif save failed (added to all commit functions)
	if (!r) this.alert(this.i18n.WSIF_SAVE_FAIL);
	return r ? this._save_to_file(true) : false;
};

//API1.0: save WoaS configuration
// PVHL: There is a very bad bug here: when options page is saved all edits are lost.
//   Also, if cumulative save is set the woas is completely corrupted. Though saved
//   changes exist in file, they don't exist in DOM and so are lost in config only save.
//   I'm not interested in finding & fixing as WoaS should be saving layout from a page
//   (probable fix is to reload file and then apply cumulative save changes before saving,
//   but the whole save process needs to be upgraded (and this issue will disappear).
//   Quick fix is to disable config-only save and save everything every time -- BUT:
//   if using external wsif file this actually WILL only save the config to html file.
//   Was: return this._save_to_file(false);
woas.cfg_commit = function() {
	// only saves to the html file; options not currently in a page
	return this._save_to_file(true);
};

//API1.0: save specific list of pages
// plist is a list of page indexes which need to be saved
// Currently just saving all the pages.
woas.commit = function(plist) {
	var r = this._wsif_ds_save(this.config.wsif_ds, this.config.wsif_ds_lock, plist);
	if (!r) this.alert(this.i18n.WSIF_SAVE_FAIL);
	return r ? this._save_to_file(true) : false;
};

//API1.0: delete specific list of pages
// plist is a list of page indexes which need to be saved (not allowed to be empty)
woas.commit_delete = function(plist) {
	// update only the native WSIF index (leaves back deleted pages)
	var r = this._wsif_ds_save(this.config.wsif_ds, this.config.wsif_ds_lock, plist);
	if (!r) this.alert(this.i18n.WSIF_SAVE_FAIL);
	// performs full save, while the single page + global header could be saved instead
	return r ? this._save_to_file(true) : false;
};

//API1.0: event called after some page is being saved
// plist can be undefined if all pages were saved
woas.after_pages_saved = function(plist) {
	// we assume that everything was saved
	if (typeof plist == "undefined") {
		this.save_queue = [];
		return;
	}
	// we remove each of the saved pages from queue (needs TESTING!)
	for(var i=0,l=plist.length;i<l;i++) {
		var p = this.save_queue.indexOf(plist[i]);
		if (p !== -1)
			this.save_queue.splice(p,1);
	}
};

//API1.0: event called when the config was successfully saved
woas.after_config_saved = function() {
	woas.cfg_changed = false;
};

/*** src/i18n.js ***/
// internationalization language resources
woas.i18n = {
	ACCESS_DENIED: "Access denied to the '%s' page.",
	ALT_BROWSER_INPUT: "This browser is not allowing the directory path to be read directly.\n\nPlease specify the full path to the '%s' file.",
	ASK_MENU_LINK: "Do you want the menu to have a link to this page?",
	B64_REQ: " (requires %s due to base64 encoding)",
	CANCEL_EDITING:"Changes to this page will not be saved.",
	CANNOT_LOCK_RESERVED: "You cannot lock a page in a reserved namespace.",
	CHOOSE_CANCEL: "\n\nIf you don't want this to happen choose Cancel.",
	CONFIRM_OVERWRITE: "Page \"%s\" already exists. Overwrite it?",
	CONFIRM_DELETE:"Are you sure you want to DELETE the '%s' page?",
	CONFIRM_DELETE_ALL1: "You are about to ERASE all your pages.\n\nDo you want to continue?",
	CONFIRM_DELETE_ALL2: "This is the last confirmation needed before ERASING all your pages.\n\nALL YOUR PAGES WILL BE LOST\n\nAre you sure you want to continue?",
	CONFIRM_DELETE_IMAGE: "Are you sure you want to delete the '%s' image?",
	CONFIRM_EXPORT: "Export '%s' to the path specified below?",
	CONFIRM_LOCK: "Do you want to use the last password entered to lock the '%s' page? ",
	CONFIRM_LOCK_LAST: "The password was last used on the '%s' page.",
	CONFIRM_READ_ONLY: "You will have to manually edit the file to revert this change.\n\nAny other changes to options will also be saved.",
	CONFIRM_REMOVE_ENCRYPT: "Do you want to remove encryption from the '%s' page?",
	CONTINUE_WAIT_LOAD: "The loading process seems stuck.\nPlease click OK to keep waiting or Cancel to break.",
	DELETE:"Delete page:",
 	DELETE_FILE:"Delete embedded file",
 	DELETE_IMAGE:"Delete embedded image",
	DELETE_PAGE_PROMPT: "Delete page:",
	DISPLAY_FULL_FILE: "Display full file",
	DUP_NS_ERROR: "Cannot duplicate into File:: or Image:: namespace!",
	DUPLICATE_PAGE: "Insert duplicate page title",
	EDITING:"Editing '%s'",
	EMPTY_TITLE: "An empty title is not allowed.",
	EMPTY_NS: "/No pages in '%s' namespace./",
	ERR_MARKER: "'%s' marker not found!",
	ERR_NO_PWD: "No password set for decrypting the '%s' page.\nPlease click the key icon and enter a password.",
	ERR_PAGE_NS: "You cannot create a page as a namespace.",
	ERR_RESERVED_NS: "Namespace '%s' is reserved.",
	ERR_SEL_FILE: "A file must be selected.",
	ERR_VAR_MARKER: "Marker variable not found!",
 	EXPORT_FILE:"Export file",
 	EXPORT_IMAGE:"Export image",
	EXPORT_OK: "%d/%d pages exported successfully.",
	FAILED_ERASE:"Saving the erased WoaS has failed!\n\nOriginal content will be restored by reloading file.",
	FILE_DISPLAY_LIMIT: "Only the first 1024 bytes are displayed.",
	FILE_SELECT_ERR: "A file must be selected.",
	FILE_SIZE: "File size",
	GO_TO_PAGE: "Go to page:",
	HEIGHT: "Height",
	IMG_LOAD_ERR: "/Image failed to load./\n",
	IMPORT_CONFIG: "Configuration imported.",
	IMPORT_INCOMPAT: "Incompatible version: %s",
	IMPORT_OLD_VER: "If this is a WoaS older than v0.9.6B, you should import it by using WoaS 0.11.x.",
	IMPORT_OK: "%s pages imported successfully (%d pages skipped)",
	IMPORT_UNRECON: "Unrecognized format.",
	INSERT_NEW:"Insert new page title",
	INVALID_ALIAS: "Invalid '%s' alias will be ignored.",
	INVALID_DATA:"Invalid collected data!",
	INVALID_PAGE: "Invalid %s page.",
	INVALID_TITLE: "Title cannot contain ':::' or any of these characters:\n# \" | < > [ ] { }",
	JS_DISABLED: "Scripts are disabled in Special::Options ('Enable safe mode')\n",
	JS_PAGE_FAIL1: "Dynamic evaluation of '%s' failed!",
	JS_PAGE_FAIL2: "\n\nError message:\n\n",
	JS_PAGE_FAIL3: "\n\nInvalid return value or type:\n\nValue: '%s'\nType: '%s'",
	LAST_MODIFIED: "Last modified: ",
	LOADING: "Loading Wiki on a Stick...",
	LOAD_ERR: "Cannot load specified file.",
	LOCK_PAGE: "Lock %s",
	MIME_TYPE: "Mime type",
	MODE_NOT_AVAIL: "File mode 0x%s is not available on this browser.",
	NO_ERROR: "No error",
	NO_JAVA:"It was not possible to use TiddlySaver Java applet nor direct Java saving.",
	NO_TIDDLY_SAVER:"The TiddlySaver Java applet was not available.",
	NOT_A_NS:"/'%s' is a reserved namespace that is not listable. See [[WoaS::Help::Namespaces#Reserved namespaces|Help]]./",
	NOT_YET_IMPLEMENTED: "Feature not implemented yet.",
	NOTE_TEXT: "NOTE:",
	PAGE_EXISTS: "A page with title '%s' already exists!",
	PAGE_NOT_EXISTS: "'%s' page does not exist.",
	PAGE_NOT_FOUND: "Page not found. Do you want to create it?",
	PRINT_MODE_WARN: "Sorry, you cannot browse the wiki while in print mode.",
	PWD_ERROR: "Passwords must match each other.",
	PWD_QUERY: "Please enter a password.",
	PWD_KEY_SIZE: "Key size: %s bits",
	READ_ONLY: "This Wiki on a Stick is read-only.",
	SAVE_ERROR:"Unable to save the '%s' file.",
	SERVER_MODE: "This Wiki on a Stick is not a local file; changes can only be saved to a local copy of the wiki. Please save this file if you want to make changes.\n\n"+
					"None of the changes made to this copy of Wiki on a Stick will be saved.",
	STATIC_NOT_FOUND: "Static page '%s' not found!",
	TIDDLY_HELP:"Please check that TiddlySaver.jar is in the same directory as this WoaS and that you have enabled Java permissions for it.",
	TOC: "Table of Contents",
	TOO_LONG_TITLE: "Maximum title length is %d characters.",
	UNSPECIFIED_JAVA_ERROR: "Please check the Java console for errors regarding the last operation and check that it's not due to your browser/Java restrictions.",
	UNSUPPORTED_BROWSER: "Your browser might not be supported. Please report a bug with your UserAgent string:\n%s",
	WIDTH: "Width",
	WRITE_PROTECTED: "This Wiki on a Stick is already write-protected.",
	WSIF_BAD_HV: "Could not locate end of header value.",
	WSIF_DS_TO_EXTERNAL: "The content of this wiki is about to be saved in WSIF format to the filename you entered.\n\nAll internal content will be deleted.\n\n",
	WSIF_DS_TO_INTERNAL: "The current wiki content is about to be stored internally.\n\nThe current WSIF data source file(s) will not be affected.",
	WSIF_DS_TO_MULTI: "The WSIF data source file is about to be rewritten as a page index WSIF file.",
	WSIF_DS_TO_SINGLE: "The current WSIF index file, listing individual page WSIF files, is about to be overwritten with page content.\n\nExisting WSIF files for pages will not be affected.",
	WSIF_EXIST: "If the filename you entered already exists it is about to be overwritten!",
	WSIF_NO_HN: "Could not locate header name.",
	WSIF_NO_VER: "Could not read WSIF version.",
	WSIF_NS_VER: "WSIF version %s is not supported!",
	WSIF_PAGES: "\n\nIf individual page files already exist for this data source file they will be overwritten.",
	WSIF_SAVE_FAIL: "Unable to save WSIF file with path given!\nCheck your data source setting in Special::Options"
};

// do not use any copyrighted wordlist here
woas.i18n.common_words = ['the','of','to' ,'and' ,'a' ,'in' ,'is' ,'it' ,'you' ,'that' ,'he' ,'was' ,'for','on' ,'are' ,'with' ,'as' ,'I' ,'his' ,'they' ,'be' ,'at' ,'one' ,'have' ,'this' ,'from' ,'or' ,'had' ,'by' , 'an', 'all' ];

/*
Used to load alternative language plug-ins (e.g.: plugins/translations).
Can also be used by plugins to add strings to i18n object, or change wording.
	obj = {
		strings:{} - strings to replace/augment built-in strings
		strings_add: bool (optional) - change existing string collection
			F: string is ignored if not found in i18n (default)
			T: string will be added to i18n collection if it doesn't exist
		common_words:[] - exclusion list used by Special::Export to build webpage metadata
		common_words_replace: bool (optional) - change existing word list
			F: common_words added to existing words if not already present (default)
			T: i18n.common_words list will be overwritten by common_words array
	}
*/
woas.i18n.load = function(obj) {
	var str, i, il, keys = {};
	if (obj.strings) {
		for (str in obj.strings) {
			if ((obj.strings_add || this.hasOwnProperty(str)) &&
					obj.strings.hasOwnProperty(str) &&
					(typeof obj.strings[str]) === 'string') {
				this[str] = obj.strings[str];
				keys[str] = true;
			}
		}
		// report strings missing from translation
		for (str in this) {
			if (!keys[str] && (typeof this[str]) === 'string') {
				woas.log('Missing - '+this.list_item(str));
			}
		}
	}
	if (obj.common_words && (obj.common_words instanceof Array)
			&& obj.common_words.length) {
		if (obj.common_words_replace) {
			this.common_words = [];
		}
		this.common_words = this.common_words.concat(obj.common_words)
			.toUnique();
	}
}

woas.i18n.list = function() {
	var str, list = [];
	for (str in this) {
		if ((typeof this[str]) === 'string') {
			list.push(this.list_item(str));
		}
	}
	return list.join('\n');
}

woas.i18n.list_item = function(key){
	return key+': "'+this[key].replace(/\n\\?/g, '\\n')
		.replace(/\t/g, '\\t')+'"';
}

/*** src/import.js ***/
// @module importer

/* NOTES ABOUT PREVIOUS VERSIONS
		0.12.0:
			* introduced some config options: new_tables_syntax, store_mts, folding_style
			* introduced plugins (which deprecate WoaS::Bootscript)
			* dropping support for all WoaS before 0.9.6B
		0.11.7:
			* 'nav_history' config option replaces 'open_last_page'
		0.11.2:
			* introduced parsing mechanism which does not mess with var declarations inside JavaScript strings
			* introduced WoaS::Hotkeys, WoaS::CSS::Core, WoaS::CSS::Custom
			* introduced woas.config.safe_mode option
			* introduced woas.config.wsif_ds* options
		0.10.7:
			* introduced WoaS::Plugins and changed WoaS::Bootscript page type from embedded to normal
		0.10.0:
			* introduced page_mts for global page modified timestamp
		0.9.7:
			* introduced WoaS::Aliases
*/

woas.importer = {
//public:
	pages_imported: 0,
	total: 0,

//private:
	// property names used to retrieve default values from stored bitmask
	_settings_props: ["i_comment_js", "i_comment_macros", "i_no_woas",
	// the last 3 options are ignored for WSIF import
					"i_config", "i_styles", "i_content"],
	// default options
	//  1 i_comment_js: false		- disable 'script' tags
	//  2 i_comment_macros: false	- disable macro blocks '<<<...>>>'
	//  4 i_no_woas: false			- do not import pages from WoaS:: namespace
	//  8 i_config: false			- import configuration (XHTML only)
	// 16 i_styles: false			- import stylesheet (XHTML only)
	// 32 i_content: true			- import content pages (XHTML only)
	// 64, 128 - the overwrite option covers bits 6,7
	//    i_overwrite: 3			- overwrite mode (0 - erase, 1 - ignore, 2 - overwrite, 3 - ask)
	_OVR_ID: 6,
	// used internally
	new_main_page: null,
	current_mts: null,
	pages: [],			// imported page objects array
	_reference: [],		// linear array containing page id or null, used privately by _get_import_vars()

	// runtime dynamic update variables
	_plugins_update: [],
	_plugins_add: [],
	_update_css: false,
	_update_hotkeys: false,
	_update_aliases: false,
	_bootscript_code: "",

	_fix_mts_val: function(mts, old_version) {
		// we did not have a timestamp before 0.10.0
		if (old_version < 100)
			return this.current_mts;
		// will catch the 'undefined' ones also
		if (!mts)
			return 0;
		// fixup the mts value in some old buggy version
		if ((old_version===100) || (old_version===101)) {
			// ignore the old null value
			if (mts === 0x4b61cbad)
				mts = 0;
		}
		return mts;
	},

	_filter_by_title: function(title) {
		// we are not using is_reserved() because will be inconsistant in case of enabled edit_override
		// PVHL: modified to allow just CSS import, no other pages
		if (!woas.importer.i_content && woas.importer.i_styles) {
			return title === "WoaS::CSS::Custom";
		}
		// check pages in WoaS:: namespace
		if (title.substr(0,6) === "WoaS::") {
			// allow CSS same as WoaS < 11.2 (and makes most sense)
			if (title === "WoaS::CSS::Custom")
				// custom CSS is allowed only when importing CSS
				return woas.importer.i_styles;
			// can we import from WoaS namespace?
			if (woas.importer.i_no_woas ||
					// never overwrite help pages with old ones
					title.indexOf("WoaS::Help") === 0 ||
					// skip other core WoaS:: pages
					woas.static_pages2.indexOf(title) !== -1) {
				return false;
			}
			// the rest are Plugins, Aliases, or Hotkeys
			return true;
		} else if (title.substr(0, 9) === "Special::" ||
				// WoaS History not imported, but is erased
				title === "WoaS History") {
			// always skip special pages and consider them system pages
			return false;
		}
		// if not on bad list, it's OK
		return true;
	},

	// function used to collect variables
	_get_import_vars: function(data, ignore_array, old_version) {
		var jstrings=[], fail = false;
		// (1) take away all javascript strings (most notably: content and titles)
		// WARNING: quoting hacks lie here!
		data = data.replace(/\\'/g, ":-"+woas.parser.marker).replace(this.reJString, function (str) {
			// restore quotes
			jstrings.push(str.substr(1, str.length-2).replace(woas.importer.reRequote, "\\'"));
			return woas.parser.marker+(jstrings.length-1).toString()+":";
		});
		// (2) rename the variables
		data.replace(/([^\\])\nvar\s+(\w+)\s*=\s*([^;]+);/g, function (str, $1, var_name, definition) {
			if (fail) return;
			// it must not be in array
			if (ignore_array.indexOf(var_name) !== -1)
				return;
			if (
					// main_page was not in config object for 0.10.8 and below
					(old_version <= 108) && (var_name === "main_page") ) {
				woas.importer.new_main_page = woas.eval(definition.replace(woas.importer.reJStringRep,
								function (str, id) { return "'"+jstrings[id]+"'";}
							), true);
				return;
			}
			// the rest of variables are for content, so exit if we don't want content
			// PVHL: modified to allow just import CSS; could make it more efficient later
			if (!(woas.importer.i_content || woas.importer.i_styles))
				return;
			// save evaluation if we don't want last modified timestamp
			if (!woas.config.store_mts && (var_name === "page_mts"))
				return;

			// evaluate the real array
			var the_var = woas.eval(definition.replace(woas.importer.reJStringRep,
								function (str, id) { return "'"+jstrings[id]+"'";}
							), true);

			// OK, we want this variable, evaluate it
			switch (var_name) {
				case "page_titles":
					// titles come before other properties, so we create all objects now
					for(var i=0,it=the_var.length;i < it;++i) {
						// call the title filtering hook
						if (woas.importer._filter_by_title(the_var[i])) {
							woas.importer.pages.push({
								title: the_var[i],
								attrs: 0,
								mts: (old_version > 97
									? 0
									: (woas.config.store_mts ? woas.importer.current_mts : 0)),
								body: null });
							// add object by-ref
							woas.importer._reference.push( woas.importer.pages[woas.importer.pages.length-1] );
						} else // no page reference
							woas.importer._reference.push( null );
					}
				break;
				case "page_attrs":
					// consistency check
					if (the_var.length !== woas.importer._reference.length) {
						woas.log("ERROR: page attributes array is not consistent ("+the_var.length+" != "+woas.importer._reference.length+")");
						fail = true;
						break;
					}
					for(var i=0,it=the_var.length;i < it;++i) {
						// skip filtered pages
						if (woas.importer._reference[i] === null)
							continue;
						woas.importer._reference[i].attrs = the_var[i];
					}
				break;
				case "page_mts": // available only on 0.10.0 and above
					// consistency check
					if (the_var.length !== woas.importer._reference.length) {
						woas.log("WARNING: page timestamps array is not consistent ("+the_var.length+" != "+woas.importer._reference.length+")");
						break;
					}
					for(var i=0,it=the_var.length;i < it;++i) {
						// skip filtered pages
						if (woas.importer._reference[i] === null)
							continue;
						woas.importer._reference[i].mts = woas.importer._fix_mts_val(the_var[i], old_version);
					}
				break;
				case "pages":
					// consistency check
					if (the_var.length !== woas.importer._reference.length) {
						woas.log("ERROR: page bodies array is not consistent ("+the_var.length+" != "+woas.importer._reference.length+")");
						fail = true;
						break;
					}
					for(var i=0,it=the_var.length;i < it;++i) {
						// skip filtered pages
						if (woas.importer._reference[i] === null)
							continue;
						woas.importer._reference[i].body = the_var[i];
					}
				break;
				// silently ignore these
				case "backstack": case "current": break;
				default:
					woas.log("Ignoring unexpected variable "+var_name);
			} // switch

		});
		// finished importing variables, clear references array
		this._reference = [];
		// clear partial results on failure
		if (fail)
			this.pages = [];
		woas.log("get_import_vars() scanned "+this.pages.length+" page definitions");
	},

	// apply options i.e. javascript security settings
	_hotfix_on_import: function(NP) {
		// only plain wiki and locked pages can be hotfixed
		if (NP.attrs < 2 && (this.i_comment_js || this.i_comment_macros))
			woas.parser.import_disable(NP, this.i_comment_js, this.i_comment_macros);
	},

	// add directly without checking for duplicates
	//NOTE: will not set 'pi' property
	_inject_import_hook: function(page) {
		page_titles.push(page.title);
		pages.push(page.body);
		page_attrs.push( page.attrs );
		// during import timestamp is already fixed when originally reading the variable
		page_mts.push(page.mts);
		// set self reference
		page.i = pages.length-1;
		return true;
	},

	_core_import_hook: function(page) {
//		woas.log("Importing page "+page.title);	//log:0
		var pi = woas.page_index(page.title);
		if (pi === -1) { // new page title
			woas.importer._inject_import_hook(page);
			page.pi = -1;
		} else { // page already existing, overwriting unless not allowed
			if (woas.importer.i_overwrite === 1 ||
					(woas.importer.i_overwrite === 3
					&& !confirm(woas.i18n.CONFIRM_OVERWRITE.sprintf(page.title)))) {
				return false;
			}
			page_titles[pi] = page.title;
			pages[pi] = page.body;
			page_attrs[pi] = page.attrs;
			page_mts[pi] = page.mts;
			page.i = page.pi = pi;
		}
		return true;
	},

	// normal import hook - shared for XHTML and WSIF import
	_import_hook: function(page) {
		if (woas.importer._core_import_hook(page)) {
			var that = woas.importer;
			that._hotfix_on_import(page);
			// take note of plugin pages and other special runtime stuff
			var _pfx = "WoaS::Plugins::";
			if (page.title.substr(0, _pfx.length) === _pfx) {
				// does plugin already exist?
				if (page.pi !== -1)
					that._plugins_update.push(page.title.substr(_pfx.length));
				else
					that._plugins_add.push(page.title.substr(_pfx.length));
			} else if (page.title === "WoaS::Aliases")
				// check if we need to update aliases and hotkeys
				that._update_aliases = true;
			else if (page.title === "WoaS::Hotkeys")
				that._update_hotkeys = true;
			else if (page.title === "WoaS::CSS::Custom")
				that._update_css = true;
			return true;
		}
		return false;
	},

	_clear: function() {
//		this.pages = [];
		this._update_css = false;
		this._update_aliases = false;
		this._update_hotkeys = false;
		this._plugins_add = [];
		this._plugins_update = [];
	},

	_old_version: null,
	_upgrade_content: function (P) {
		var that = woas.importer;
		// fix the old bootscript page
		if (that._old_version < 120) {
			if (P.title === "WoaS::Bootscript") {
				// convert old base64 bootscript to plain text
				if (that._old_version < 107)
					that._bootscript_code = woas.base64.decode(P.body);
				else
					that._bootscript_code = P.body;
				that.pages_imported++;
				woas.progress_status(that.pages_imported/that.pages.length);
				return false;
			}
		} // since 0.12.0 we no more have a bootscript page

		// check that imported image is valid
// PVHL: TODO should add import options to allow/deny/unlock encrypted pages
// There is a downside to this quick fix: an encrypted image that has issues from
// earlier versions won't be fixed. Only way to fix is to either decrypt now or to
// add the fix code to the normal image opening code with an offer to fix the issue.
// Will do one or both of these later. (For now just need to be able to import my
// encrypted password image =)
		if (P.attrs & 8 && !(P.attrs & 2)) {
			// if the image is not valid as-is, attempt to fix it
			if (!that.reValidImage.test(P.body)) {
				// do not continue with newer versions or if not base64-encoded
				if ((that._old_version>=117) || !woas.base64.reValid.test(P.body)) {
					woas.log("Skipping invalid image "+P.title);
					return false;
				}
				// we assume that image is double-encoded
				P.body = woas.base64.decode(P.body);
				// check again for validity
				if (!that.reValidImage.test(P.body)) {
					woas.log("WARNING: skipping invalid image "+P.title); //log:1
					return false;
				}
				woas.log("Fixed double-encoded image "+P.title); //log:1
			}
			// try to fix the 'undefined' mime type bug
			if (that._old_version < 120) {
				if (that.reImageBadMime.test(P.body))
					// attempt to find the correct mime
					P.body = "data:"+woas._guess_mime(P.title)+P.body.substr(14);
			}
		} // check images

		// fix the trailing nul bytes bug in encrypted pages
		// extended from 0.10.4 to 0.12.0 because was not fixed on new pages
		if ((that._old_version>=102) && (that._old_version<120)
			&& (P.attrs & 2)) {
			var rest = P.body.length % 16;
			if (rest) {
				woas.log("removing "+rest+" trailing bytes from page "+P.title); //log:1
				while (rest-- > 0) {P.body.pop();}
			}
		}

		// proceed to actual import
		if (that._import_hook(P)) {
			++that.pages_imported;
			woas.progress_status(that.pages_imported/that.pages.length);
		}
		return true;
	},

	_import_content: function(old_version) {
		this._old_version = old_version;
		for (var i=0; i < this.pages.length; i++) {
			this._upgrade_content(this.pages[i]);
		}
	},

	// actual import of html file
	do_import: function(ct) {
		// initialize
		this.pages_imported = 0;
		this.total = 0;

		var fail=false;

		do { // a fake do...while to ease failure return

		// get WoaS version
		var old_version,
			ver_str = ct.match(/var woas = \{"version":\s+"([^"]+)"\s*\};(\r\n|\n)/);
		if (!ver_str || !ver_str.length) {
			woas.alert("Could not determine WoaS version\n"+woas.i18n.IMPORT_OLD_VER);
			fail = true;
			break;
		}
		ver_str = ver_str[1];
		woas.log("Imported file version string: "+ver_str);	// log:1
		switch (ver_str) {
			case "0.9.6B":
			case "0.9.7B": // never released officially
				ver_str = ver_str.substr(0, ver_str.length-2);
			case "0.10.0": case "0.10.1":
			case "0.10.2": case "0.10.3":
			case "0.10.4": case "0.10.5":
			case "0.10.6": case "0.10.7":
			case "0.10.8": case "0.10.9":
			case "0.11.0": case "0.11.1":
			case "0.11.2": case "0.11.3":
			case "0.11.4": case "0.11.5":
			case "0.11.6": case "0.11.7":
			case "0.11.8": case "0.11.9":
			case "0.12.0":
			old_version = Number(ver_str.substr(2).replace(/\./g, ""));
				break;
			default:
				woas.alert(woas.i18n.IMPORT_INCOMPAT.sprintf(ver_str)+woas.i18n.IMPORT_OLD_VER);
				fail=true;
		}
		if (fail) break;

		// import the variables
		var	imported_css = null,
			// used during import from older versions
			old_cfg;
		if (this.i_config)
			old_cfg = woas.clone(woas.config);

		this.new_main_page = woas.config.main_page;

		// locate the random marker
		var old_marker = ct.match(/\nvar __marker = "([A-Za-z\-\d]+)";(\r\n|\n)/);
		if (!old_marker) {
			woas.alert(woas.i18n.ERR_MARKER);
			fail = true;
		}
		if (fail) break;
		old_marker = old_marker[1];

		// import the CSS head tag in versions before 0.11.2
		if (this.i_styles && (old_version < 112)) {
			ct.replace(this.reOldStyleBlock, function (str, $1) {
				imported_css = $1;
			});
		} // 0.11.2+, we'll manage CSS import at the page level

		var data = woas._extract_src_data(old_marker, ct, true, this.new_main_page, true);
		// some GC help: we no more need the big content variable
		ct = null;

		if (this.i_config) {
			var cfgStartMarker = 'woas["'+'config"] = {',
				// grab the woas config definition
				cfg_start = data.indexOf(cfgStartMarker),
				cfg_found = false;

			if (cfg_start !== -1) {
				var cfg_end = data.indexOf('}', cfg_start+cfgStartMarker.length);
				if (cfg_end !== -1) {
					woas.config = woas.eval(data.substring(cfg_start+cfgStartMarker.length-1, cfg_end+1), true);
					cfg_found = !woas.eval_failed;
				}
			}

			if (!cfg_found) {
				woas.log("Failed to import old configuration object");
			} else {
				// add the new debug option
				if (old_version<=107)
					woas.config.debug_mode = old_cfg.debug_mode;
				// add the new safe mode
				if (old_version < 112) {
					woas.config.safe_mode = old_cfg.safe_mode;
					//NOTE: WSIF datasource options are not imported at all
				}
				// renamed one config option
				if (old_version < 117) {
					woas.config.nav_history = woas.config.open_last_page;
					delete woas.config.open_last_page;
				}
				// introduced new options
				if (old_version < 120) {
					woas.config.new_tables_syntax = old_cfg.new_tables_syntax;
					woas.config.store_mts = old_cfg.store_mts;
					woas.config.folding_style = old_cfg.folding_style;
				}
				// check for any undefined config property - for safety
				for(p in woas.config) {
					// remove things from the past
					if (typeof old_cfg[p] === "undefined") {
						// PVHL: my version doesn't have a separate version#
						if (p = "import_settings") {
							woas.config.import_wsif = woas.config.import_woas = woas.config[p];
							delete woas.config[p];
						} else {
							woas.log("BUG: removing invalid config option '"+p+"'");
							delete woas.config[p];
							continue; // PVHL: this breaks out of do loop! Why?
						}
					}
					// PVHL: I guess this would be for a broken option in old file
					if ((typeof woas.config[p] == "undefined") && (typeof old_cfg[p] != "undefined"))
						woas.config[p] = old_cfg[p];
				}

				// put back the old values for WSIF datasource
				woas.config.wsif_author = old_cfg.wsif_author;
				woas.config.wsif_ds = old_cfg.wsif_ds;
				// below are not being used - Check that save doesn't write out nulls
				woas.config.wsif_ds_lock = null; //old_cfg.wsif_ds_lock;
				woas.config.wsif_ds_multi = null; //old_cfg.wsif_ds_multi;
			} // done importing config object
		} // i_config

		// modified timestamp for pages before 0.10.0
		this.current_mts = Math.round(new Date().getTime()/1000);

		// import the pages data
		this._get_import_vars(data, ['woas', '__marker', 'version', '__config'],
							old_version);
		// some GC help
		data = null;

		// apply upgrade fixes
		if (this.i_content || this.i_styles) {
			this._import_content(old_version);
			this.total = this.pages.length;
			// GC cleanup
			this.pages = [];
		}

		// eventually add the new missing page
		if (old_version <= 112) {
			// take care of custom CSS (if any)
			if (imported_css !== null) {
				// import it as a page
				this._import_hook( {
					title: "WoaS::CSS::Custom",
					attrs: 0,
					mts: woas.config.store_mts ? this.current_mts : 0,
					body: imported_css
				} );
			}
		}
		// set the new config variable
		if (this.i_config) {
			if (old_version<=108)
				woas.config.main_page = old_cfg.main_page;
			// apply the new main page if that page exists
			if ((this.new_main_page !== old_cfg.main_page) && woas.page_exists(this.new_main_page))
				woas.config.main_page = this.new_main_page;
		}

		} while (false); // fake do..while ends here

		// fix configuration for older versions
		if (old_version < 114) {
			if (!woas.config.nav_history) {
				// reset some variables which were not reset in those older versions
				backstack = [];
				current = woas.config.main_page;
			}
		}

		// if there is bootscript code, create a new plugin for it
		// skip empty bootscripts and also default bootscript
		var trimmed_bs = woas.trim(this._bootscript_code);
		if ((trimmed_bs.length !== 0) && (trimmed_bs !== '/* insert here your boot script */')
			&& (trimmed_bs !== '// Put here your boot javascript')) {
			var chosen_name = "WoaS::Plugins::Bootscript", base_name = chosen_name, i=0;
			while (page_titles.indexOf(chosen_name) !== -1) {
				chosen_name = base_name + "_" + (i++).toString();
			}
			woas.log("Old bootscript code will be imported as "+chosen_name);
			// now create such plugin by directly importing it
			this._import_hook( {
				title: chosen_name,
				body: "/* This JavaScript code was automatically imported by WoaS from your former WoaS::Bootscript */\n"+this._bootscript_code,
				attrs: 0,
				mts: woas.config.store_mts ? this.current_mts : 0
			} );
		}

		// always update run-time stuff, even on failure
		this._after_import();

		// clear everything else
		this._clear();

		// return false on failure
		return !fail;
	},

	_after_import: function() {
		var that = woas.importer;
		// refresh in case of CSS, aliases and/or hotkeys modified
		if (that._update_css)
			woas.css.set(woas.get_text("WoaS::CSS::Core")+"\n"+woas.get_text("WoaS::CSS::Custom"));
		if (that._update_aliases)
			woas._load_aliases(woas.get_text("WoaS::Aliases"));
		if (that._update_hotkeys)
			woas.hotkey.load(woas.get_text("WoaS::Hotkeys"));

		// add/update plugins
		for(var i=0,it=that._plugins_update.length;i < it;++i) {
			woas.plugins.update(that._plugins_update[i]);
		}
		for(var i=0,it=that._plugins_add.length;i < it;++i) {
			// plugin should be on the list
			woas.plugins._all.push(that._plugins_add[i]);
			woas.plugins.enable(that._plugins_add[i]);
		}

	},

	// regular expressions used to not mess with title/content strings
	reRequote: new RegExp(":-"+woas.parser.marker, "g"),
	reJString: new RegExp("'[^']*'", "g"),
	reJStringRep: new RegExp(woas.parser.marker+"(\\d+):", "g"),
	reValidImage: /^data:\s*[^;]*;\s*base64,\s*/,
	reImageBadMime: /^data:undefined;\s*base64,\s*/,
	reOldStyleBlock: new RegExp("<"+"style\\s.*?type=\"?text\\/css\"?[^>]*>((\\n|.)*?)<"+"\\/style>", "i")

};

// called from Special::Import - import WoaS from XHTML file
// PVHL: this, like other areas, needs to be rewritten to be atomic; certain
//   failures can leave things in an unknown state.
woas.import_wiki = function() {
	var cfg = this.importer.i_config, pgs = woas.importer.i_content,
		sty = this.importer.i_styles, ct, rv, v, msg;
	if (!(cfg || pgs || sty) || !woas._import_pre_up(false)) {
		return false;
	}

	// set hourglass
	this.progress_init("Import WoaS");

	// file will be loaded as ASCII to overcome browsers' limitations
	ct = this.load_file(null, this.file_mode.ASCII_TEXT);
	if (!ct) {
		if (ct === false) {
			this.alert(this.i18n.LOAD_ERR);
		}
		// remove hourglass
		this.progress_finish();
		return false;
	}

	rv = this.importer.do_import(ct), v = {};

	// remove hourglass
	this.progress_finish();

	if (rv) {
		if (cfg) {
			// make sure any configuration change is represented
			v.fix_h = this.config.fixed_header;
			v.fix_m = this.config.fixed_menu;
			v.no_debug = !this.config.debug_mode;
			v.no_mts = !this.config.store_mts;
			this.ui.display(v);
		}
		// inform about config & imported pages
		this.alert((cfg ? this.i18n.IMPORT_CONFIG : '') +
			(pgs || sty ? (cfg ? '\n\n' : '') + this.i18n.IMPORT_OK.sprintf(
			this.importer.pages_imported+"/"+this.importer.total,
			this.importer.total - this.importer.pages_imported) : ''));
	}
	// save if successful import or if we have erased the wiki
	if (rv || this.importer.i_overwrite === 0) {
		this.full_commit(); // PVHL: this could have failed!
		this.ui._import_load();
		this.ui.refresh_menu();
	}
	// PVHL: not going to main page any more as it could be disorienting;
	return rv;
};

woas._file_ext = function(fn) {
	var m=fn.match(/\.(\w+)$/);
	if (m === null) return "";
	return "."+m[1];
};

woas._import_pre_up = function(wsif) {
	var tmp, old_is;
	// check if this WoaS is read-only
	if (!this.config.permit_edits) {
		this.alert(woas.i18n.READ_ONLY);
		return false;
	}
	tmp = wsif ? woas.config.import_wsif : woas.config.import_woas, old_is = tmp;
	// now store these values
	tmp = this.bitfield.get_object(this.importer, this.importer._settings_props);
	// set also bits for overwrite options
	tmp = this.bitfield.set(tmp, this.importer._OVR_ID, this.importer.i_overwrite & 1, tmp);
	tmp = this.bitfield.set(tmp, this.importer._OVR_ID+1, this.importer.i_overwrite & 2, tmp);
	if (wsif) woas.config.import_wsif = tmp;
	else woas.config.import_woas = tmp;
	// check if configuration changed
	this.cfg_changed |= (tmp !== old_is);
	// check if user wants total erase before going on
	if (this.importer.i_overwrite === 0) {
		if (!this.erase_wiki())
			return false;
	}
	return true;
};

// called from Special::ImportWSIF
woas.import_wiki_wsif = function() {
	if (!woas._import_pre_up(true))
		return false;

	// automatically retrieve the filename (will call load_file())
	var done = woas._native_wsif_load(null, false /* no locking */, false /* not native */, 0,
			this.importer._upgrade_content, this.importer._filter_by_title,
			this.importer._after_import);
	if (done === false && (woas.wsif.emsg !== null))
		this.crash(woas.wsif.emsg);

	if (done !== false) {
		// add some info about total pages
		var skipped;
		if (this.wsif.expected_pages !== null) {
			skipped = this.wsif.expected_pages-done;
			done = String(done)+"/"+woas.wsif.expected_pages;
		} else skipped = 0;
		this.alert(woas.i18n.IMPORT_OK.sprintf(done, skipped));
		this.ui.refresh_menu();
		// now proceed to actual saving
		this.commit(woas.wsif.imported);
	} else if (this.importer.i_overwrite === 0) {
			// always save if we have erased the wiki
			this.full_commit(); // PVHL: this could have failed!
	}

	return done;
};

/*** src/export.js ***/
// PVHL: DEPRECATED - these arrays moved here from core.js; not used elsewhere
woas.unexportable_pages = ["New Page", "Duplicate Page", "Backlinks", "Erase Wiki", "Edit CSS",
								"Go to", "Delete Page", "Search"];
woas.unexportable_pages2 = ["WoaS::CSS", "WoaS::Aliases", "WoaS::Hotkeys", "WoaS::Plugins"];

/* Just needing to look at these for a bit
woas.static_pages2 = [
	"WoaS::Plugins", "WoaS::CSS::Boot", "WoaS::CSS::Core", "WoaS::Help",
	"WoaS::ImportSettings", "WoaS::Template::Search", "WoaS::Template::Info"
];
*/

// WoaS 'exporter' module
woas.exporter = {
	_unix_norm: false,
	_default_ext: 'html',

	// arrays/objects using during export
	_title2fn: {},
	_further_pages: [],
	_export_fnames_array: [],
	_settings: {},
	
	clear: function() {
		this._export_fnames_array = [];
		this._title2fn = {};
		this._further_pages = [];
		this._settings = {};
	},
	
	// export wiki in XHTML/CSS and attachment files
	do_export: function () {
		this._settings.custom_scripts = "";
		var data;
		if (this._settings.js_mode==2) {
			//export all active plugins as javascript code
			var js_fn;
			for(var pi=0,pt=woas.plugins._active.length;pi<pt;++pi) {
				data = woas.plugins.get(woas.plugins._active[pi]);
				if (woas.plugins.is_external) {
					// data is an array of sources, go through it
					for(var i=0;i<data.length;++i) {
						this._settings.custom_scripts += '<'+'sc'+'ript type="text/javascript" src="'+data[i]+'"><'+"/script>\n";
					}
				} else {
					js_fn = woas._unix_normalize(woas.plugins._active[pi])+".js";
					if (woas.save_file(this._settings.xhtml_path+js_fn,
										woas.file_mode.ASCII_TEXT, data)) {
						this._settings.custom_scripts += '<'+'script type="text/javascript" src="'+js_fn+'"><'+"/script>\n";
					}
				}
			}
		}

		var pg, pi, l, fname = "", done = 0, total = 0, mnupos;
		data = null;
		for (pi = 0, l = page_titles.length; pi < l; pi++) {
			pg = page_titles[pi];
			// do skip physical special pages
			if (pg.match(/^Special::/)) continue;
			if (woas.static_pages2.indexOf(pg) !== -1) continue;
			// skip also the unexportable WoaS pages
			if (woas.unexportable_pages2.indexOf(pg) !== -1) continue;
			// do skip menu pages (they are already included in each page)
			if (pg.substr(-6) === '::Menu' && pg !== 'WoaS::Help::Menu') {
				continue;
			}
			data = woas.get_text_special(pg);
			// skip pages which could not be decrypted
			if (data === null) continue;
			fname = this._get_fname(pg, true);
			// will skip WoaS::Plugins::* and WoaS::Aliases
			if (fname === '#') {
	//			woas.log("skipping "+pg);
				continue;
			}
			++total;
			if (woas.is__embedded(pi)) {
				if (woas.is__image(pi)) {
					if (!woas._b64_export(data, this._settings.img_path+fname))
						break;
					// image export was successful, continue to next page
					else { ++done; continue; }
				} else {
					// fully export the file
					if (!woas._b64_export(data, this._settings.xhtml_path+fname))
						break;
					// image export was successful, continue to next page
					else { ++done; continue; }
				}
			} else
				data = woas.export_parse(data, this._settings.js_mode);
			if (!this._one_page(data, pg, fname, woas.config.store_mts ? page_mts[pi] : 0))
				break;
			++done;
		}
		woas.log("pages yet to process: "+this._further_pages);	// log:1
		// process further pages
		var title;
		// exchange arrays to parse at some extent
		var eatable = this._further_pages.slice(0);
		while (eatable.length) {
			this._further_pages = [];
			for(var i=0,el=eatable.length;i < el;i++) {
				title = eatable[i];
				data = woas.get_text_special(title);
				if (data===null) {
					woas.log("cannot process "+title);
					continue;
				}
				// TODO: allow special pages to have extended attributes
				data = woas.export_parse(data, this._settings.js_mode);
				++total;
				if (this._one_page(data, title, this._title2fn[title]))
					++done;
			}
			eatable = this._further_pages.slice(0);
		}
		// return total exported pages/objects
		return [done, total];
	},
	
	_one_page: function (data, title, fname, mts) {
		data = woas.utf8.do_escape(data);
		// prepare the raw text for later description/keywords generation
		var raw_text = woas.trim(woas.xhtml_to_text(data)), exp_menu = '',
			ns, mpi, tmp;
		if (this._settings.exp_menus) {
			ns = woas.get_namespace(title);
			// get submenu, if available, from first available namespace
			if (!/^WoaS::Help/.test(ns)) {
				while (ns !== "") {
					mpi = woas.page_index(ns + "::Menu");
					if (mpi !== -1) {
						tmp = woas.get__text(mpi);
						if (tmp !== null)
							exp_menu = tmp;
						break;
					}
					tmp = ns.lastIndexOf("::");
					ns = tmp === -1 ? "" : ns.substring(0, tmp);
				}
			}
			if (!exp_menu) {
				exp_menu = woas.get_text("::Menu") || "";
			}
			// parse the exported menu
			if (exp_menu) {
				exp_menu = woas.parser.parse(exp_menu, true, this._settings.js_mode);
				if (this._settings.js_mode) {
					woas.scripting.activate("menu");
				}
				// fix also the encoding in the menus
				exp_menu = 'div id="woas_menu_wrap"><'+'div id="woas_menu_pad"><'+
					'div id="woas_menu">'+woas.utf8.do_escape(exp_menu)+'<'+
					'/div><'+'/div><'+'/div><';
			}
		}
		data = '<'+'div id="woas_header_wrap"><'+'div id="woas_header"><'+
			'span id="woas_title">'+title+'<'+'/span><'+'/div><'+'/div><'+
			'div id="woas_content"><'+exp_menu+'div id="woas_page_wrap"><'+
			'div id="woas_page">'+data+'<'+'/div>'+(mts ? '<'+
			'div id="woas_mts">'+woas.last_modified(mts)+'<'+'/div>' : '')+
			'<'+'/div><'+'/div>';
		// craft a nice XHTML page
		data = "<"+"title>"+woas.xhtml_encode(title)+"<"+"/title>"+
			// add the exported CSS
			this._settings.css+
			// add the last-modified header
			(mts ? '<'+'meta http-equiv="last-modified" content="'+
			(new Date(mts*1000)).toGMTString()+'" />'+"\n" : '')+
			// other useful META stuff
			'<'+'meta name="generator" content="Wiki on a Stick v'+
			woas.version+' - http://stickwiki.sf.net/" />'+"\n"+
			'<'+'meta name="keywords" content="'+
			woas.utf8.do_escape(woas._attrib_escape(_auto_keywords(raw_text)))+
			'" />'+"\n"+'<'+'meta name="description" content="'+
			woas.utf8.do_escape(woas._attrib_escape(raw_text.replace(/\s+/g,
			" ").substr(0,max_description_length)))+'" />'+"\n"+
			this._settings.meta_author+this._settings.custom_scripts+'<'+
			'/head><'+'body class="woas_export'+(exp_menu ? '' :
			' woas_export_no_menu')+'">'+data+'<'+'/body><'+'/html>\n';
		raw_text = null;
		return woas.save_file(this._settings.xhtml_path+
			fname, woas.file_mode.ASCII_TEXT, woas.DOCTYPE+woas.DOC_START+data);
	},
	
	_get_fname: function (title, create_mode) {
		if (typeof(this._title2fn[title]) != 'undefined') {
			// return a cached title
			if (!create_mode) {
				// do not escape the null-page URL
				if (this._title2fn[title] == '#')
					return '#';
				return escape(this._title2fn[title]);
			}
			return this._title2fn[title];
		}
		var sp, orig_title = title;
		// handle the valid exportable special pages
		if (title.match(/::$/)) {
			sp = true;
		} else if (woas.is_reserved(title)) {
			var nogo;
			if (title.match(/^WoaS::/))
				nogo = (woas.unexportable_pages2.indexOf(title)!==-1);
			else if (title.match(/^Special::/))
				nogo = (woas.unexportable_pages.indexOf(title.substr(9)) !== -1);
			else // other reserved pages, deny
				nogo = true;
			if (nogo) {
				woas.log("Reserved page will not be exported: "+title);
				this._title2fn[title] = "#";
				return "#";
			} else // do export these special pages later
				// PVHL: but don't rewrite actual help pages
				if (!title.match("WoaS::Help")) sp = true;
		}
		var pi;
		if (sp) {
			// save a reference to this namespace or reserved page
			if (this._further_pages.indexOf(title)==-1)
				this._further_pages.push(title);
		} else {
			pi=woas.page_index(title);
			if (pi === -1) {
				woas.alert(woas.i18n.PAGE_NOT_EXISTS.sprintf(title));
				this._title2fn[title] = "#";
				return "#";
			}
			// beware: a special page or namespace index page cannot be main page
			// considering the below code
			if (this._settings._main_index && (title === woas.config.main_page)) {
				this._title2fn[title] = "index."+ this._default_ext;
				this._export_fnames_array.push(this._title2fn[title]);
				return this._title2fn[title];
			}
		}
		var ext = "";
		if (!sp && woas.is__embedded(pi)) {
			// remove the namespace
			title = title.substr(title.indexOf("::")+2);
	//		if (!this.is__image(pi))
	//			ext = "."+this._default_ext;
	//		emb = true;
		} else {
			ext = "."+this._default_ext;
	//		emb = false;
		}
		var fname = title
		// convert UTF8 characters to something else (cross-browser safe cheap solution)
		.replace(/[^\u0000-\u007F]+/g, function ($1) {
			var l=$1.length, r="";
			for(var i=0;i < l;i++) {
				/*switch ($1[i]) {
					// TODO: add most common diacritics
					case "\u00e2":
						r+="a";
						break;
					default:
						r+="_";
				}*/
				// until that day ...
				r += ($1[i] == "\u00e2") ? "a" : "_";
			}
			return r;
		})
		// escape some path-unsafe characters
		.replace(/[:\\\/<>?#=!]+/g, function($1) {
			return "_".repeat($1.length);
		});
		// fix the directory separator chars
		if (this._settings._unix_norm)
			fname = woas._unix_normalize(fname);
		else
			fname = fname.replace(/::/g, " - ");
		var test_fname = fname+ext, i=0;
		while (this._export_fnames_array.indexOf(test_fname) !== -1) {
			woas.log(test_fname+" already created, checking next fname");	// log:1
			test_fname = fname+"_".repeat(++i)+ext;
		}
	//	if (i)		_export_replace_fname[fname+"_".repeat(i-1)+ext] = test_fname;
		this._export_fnames_array.push(test_fname);
		this._title2fn[orig_title] = test_fname;
		if (!create_mode)
			return escape(test_fname);
		return test_fname;
	}

};

woas._unix_normalize = function(s) {
	return s.toLowerCase().replace(/\s+/g, "_").replace(/::/g, "-")
};

// save a base64 data: stream into an external file
woas._b64_export = function(data, dest_path) {
	// decode the base64-encoded data
	data = this.base64.decode(data.replace(/^data:\s*[^;]*;\s*base64,\s*/, ''));
	// attempt to save the file
	return this.save_file(dest_path, this.file_mode.BINARY, data);
};

woas._attrib_escape = function(s) {
	return s.replace(/"/g, '&quot;');
};

woas.export_parse = function (data, js_mode) {
	// a normal wiki page, parse it and eventually execute the attached javascript
	data = this.parser.parse(data, true, js_mode);
	if (js_mode) {
		this.setHTMLDiv(d$("woas_page"), data);
		this.scripting.activate("page");
		data = this.getHTMLDiv(d$("woas_page"));
	}
	return data;
};

woas.export_wiki = function() {
	var sep_css;
	// parse user export options
	try {
		this.exporter._settings.xhtml_path = d$("woas_ep_xhtml").value;
		this.exporter._settings.img_path = d$("woas_ep_img").value;
		this.exporter._settings.js_mode = 0;
		if (d$("woas_cb_js_dyn").checked)
			this.exporter._settings.js_mode = 1;
		else if (d$("woas_cb_js_exp").checked)
			this.exporter._settings.js_mode = 2;
		sep_css = d$("woas_cb_sep_css").checked;
		this.exporter._settings.exp_menus = d$("woas_cb_export_menu").checked;
		this.exporter._settings._main_index = d$("woas_cb_index_main").checked;
		this.exporter._default_ext = d$("woas_ep_ext").value;
		this.exporter._settings.meta_author = this.trim(d$("woas_ep_author").value);
		if (this.exporter._settings.meta_author.length)
			this.exporter._settings.meta_author = '<'+'meta name="author" content="'+this._attrib_escape(this.xhtml_encode(this.exporter._settings.meta_author))+'" />'+"\n";
		this.exporter._settings._unix_norm = d$("woas_cb_unix_norm").checked;
	} catch (e) { this.crash(e); return false; }

	this.progress_init("Exporting XHTML");

	this.exporter._settings.css = this.css.get();
	// add some other CSS which is not used by live WoaS
	this.exporter._settings.css += "\n.woas_broken_link { color: red; text-decoration: underline; }\n";
	if (sep_css) {
		this.exporter._settings.css_path = "woas.css";
		this.exporter._export_fnames_array.push(this.exporter._settings.css_path);
		this.save_file(this.exporter._settings.xhtml_path+this.exporter._settings.css_path, this.file_mode.ASCII_TEXT, this.exporter._settings.css);
		this.exporter._settings.css = "<"+"link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""+this.exporter._settings.css_path+"\" /"+">";
		} else
	this.exporter._settings.css = "<"+"style type=\"text/css\">"+this.exporter._settings.css+"<"+"/style>";

	// actual exporting
	var stats = this.exporter.do_export();

	// refresh if javascript was run
	if (this.exporter._settings.js_mode) {
		this.set_current(current, false);
	}
	// clear allocated resources used during export
	this.exporter.clear();

	this.progress_finish();
	this.alert(this.i18n.EXPORT_OK.sprintf(stats[0], stats[1]));
	return true;
};

var max_keywords_length = 250;
var max_description_length = 250;
// proper autokeywords generation functions begin here
var reKeywords = new RegExp("[^\\s\x01-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]{2,}", "g");
function _auto_keywords(source) {
	if (!source.length) return "";
	var words = source.match(reKeywords);
	if ((words===null) || !words.length) return "";
	var nu_words = [], density = [], wp=0, cond;
	for(var i=0;i < words.length;i++) {
		if (words[i].length === 0)
			continue;
		cond = (woas.i18n.common_words.indexOf(words[i].toLowerCase())<0);
		if (cond) {
			wp = nu_words.indexOf(words[i]);
			if (wp < 0) {
				nu_words = nu_words.concat(new Array(words[i]));
				density[nu_words.length-1] = {"i":nu_words.length-1, "w":1};
			} else
				density[wp].w = density[wp].w + 1;
		}
	}
	if (!density.length) return "";
	words = [];
	var keywords = "", nw = "";
	density = density.sort(function(a,b){return b.w - a.w;});
	var ol=0;
	for(i=0;i < density.length;i++) {
		nw = nu_words[density[i].i];
		if (ol+nw.length > max_keywords_length)
			break;
		keywords = keywords+","+nw;
		ol+=nw.length;
	}
	return keywords.substr(1);
}

// used to export files/images
woas.export_file = function(page, dest_path) {
	var pi=this.page_index(page);
	if (pi==-1)
		return false;
	var data=this.get__text(pi);
	if (data==null)
		return false;
	// attempt to save the file (binary mode)
	return this.save_file(dest_path, this.file_mode.BINARY, this.base64.decode(data));
};

// export a base64-encoded image to a file
woas.export_image = function(page, dest_path) {
	var pi=this.page_index(page);
	if (pi==-1)
		return false;
	var data=this.get__text(pi);
	if (data==null)
		return false;
	return this._b64_export(data, dest_path);
};

/*** src/wsif.js ***/
// @module wsif
/**
PVHL: WoaS 0.12.0 has multiple ways to corrupt files, including WSIF files;
e.g.: the whole wiki was being deleted if there was a data source path error.
I have modified the WSIF object to allow loading and saving of the files
WoaS is able to export with Special::ExportWSIF. To make this safer, I have
added a new header: 'wsif.type: index'. Recursion is allowed if the root file
is an index and/or the external file has a mime-type. This works in testing
with image files, but only in Firefox because binary load and save doesn't work
yet in other browsers. WoaS 0.12.0 fails silently, possibly corrupting the wiki.

Given the above it makes no sense to allow blob saves in WoaS, given other
browsers can neither load, edit, or save the resulting files. I have therefore
disabled blob saving until the capability works cross-browser. Also, the default
was to save mime files as a blob; this has been changed.

A multi-file index is indicated by the 'wsif.type: index' wsif header and is only
allowed in the root wsif index file (now generated by save). This allows safe
saving of multifile wsif files (the index file was corrupted previously if
multi_file wasn't set)

TODO:

* make any save failure cancel the save; this will help protect data and speed up
  error discovery

* make multi-file save only save the file that was changed/added and the index;
  it is very slow right now and this would improve things greatly -- most of the
  code to do this is already present.

  It would also be a good idea to only save index if:
    * a new page is added
    * page name is changed
    * page is deleted
  Given that we can't delete files it would only be necessary to read the current
  index file, modify it, and write it back out; not sure the time saved is worth
  the extra effort: index files seem to be created very quickly.
*/

woas.wsif = {
	version: "1.3.1",			// version of WSIF format being used
	DEFAULT_INDEX: "index.wsif",
	ds_multi: false, // just to document; set by wsif loader if index file was loaded
	emsg: null,
	imported: [],				// _native_page_def() will always add imported pages here
	expected_pages: null,
	global_progress: 0,
	generator: { version: null, name: null },
	header: function(header_name, value) {
		return header_name+": "+value+"\n";
	},
	inline: function(boundary, content) {
		return "\n--"+boundary+"\n"+content+"\n--"+boundary+"\n";
	},
	_generate_random_boundary: function(old_boundary, text) {
		var b = old_boundary;
		if (!b.length)
			b = _random_string(10);
		while (text.indexOf(b) != -1) {
			b = _random_string(10);
		}
		return b;
	},
	do_error: function(msg) {
		woas.log("WSIF ERROR: "+msg);	//log:1
		this.emsg = msg;
	},
	
	reMimeMatch: /^data:\s*([^;]*);\s*base64,\s*/
};

// properly calculate an incremental value for version strings
// we consider each place is worth 10^2
woas._version_to_int = function(s) {
	// split into all tokens
	var v = s.split("."), rv = 0;
	for(var i=v.length-1;i >= 0;--i) {
		rv += (v[i] * Math.pow(100, v.length-i-1));
	}
	return rv;
};

woas._normver = function(s) {
	// to be enabled after 1.0.0 release
	//var rv = this._version_to_int(s);
	//if (rv >= 10000) return rv;
	return parseInt(s.replace(/\./g, ""));
};

// default behavior:
// - wiki pages go inline (utf-8), no container encoding
// - embedded files/images go outside as blobs - disabled; now inline ... wasn't default here
// - encrypted pages go inline in base64
// inline_wsif is currently always true (external blobs are disabled until it works properly)
woas._native_wsif_save = function(path, src_fname, locking, single_wsif, inline_wsif, author,
							save_all, plist) {

	// PVHL: plist is no longer optional, but disabled until the broken commit code is fixed
	// sometimes plist is used as a list of all pages to be saved, sometimes as a list of single
	// pages to be saved. Obviously this is a conflict in operation.
	// plist should only be used in multi-wsif mode where separate pages exist. It is almost
	// certainly faster to create pages for saving than to load file and manipulate content,
	// so this is best even after WoaS save process is changed to use pages to create file.
	plist = [];
	inline_wsif = true;
	this.progress_init("WSIF save");
	
	// prepare the extra headers
	var extra = this.wsif.header('wsif.version', this.wsif.version);
	extra += this.wsif.header('wsif.generator', 'woas');
	extra += this.wsif.header('wsif.generator.version', this.version);
	if (author.length)
		extra += this.wsif.header('woas.author', author);

	// boundary used for inline attachments
	var full_wsif = "", boundary = __marker,
		p = boundary.indexOf("-"),
		l, done = 0, full_save;
	// use the 1st part of the global marker
	if (p !== -1)
		boundary = boundary.substr(0,p);

	if (plist.length) {
		l = plist.length;
		full_save = false;
	} else {
		full_save = true;
		l = page_titles.length;
	}
	// save count of total pages which need to be exported
	this.wsif.expected_pages = l;
	// the attributes prefix, we do not use the page index here for better versioning
	var pfx = "woas.page.",
		pi, pl;
	for (var ipi=0;ipi < l;++ipi) {
		if (full_save)
			pi = ipi;
		else
			pi = plist[ipi];
		// do skip physical special pages
		if (!save_all) {
			if (/^(Special::|WoaS::Help|WoaS History$)/.test(page_titles[pi])) continue;
			if (this.static_pages2.indexOf(page_titles[pi]) !== -1) continue;
		}
		var record = this.wsif.header(pfx+"title", this.ecma_encode(page_titles[pi]))+
					this.wsif.header(pfx+"attributes", page_attrs[pi]);
		// specify timestamp only if not magic
		if (this.config.store_mts && (page_mts[pi] !== 0))
			record += this.wsif.header(pfx+"last_modified", page_mts[pi]);
		var ct = null, orig_len = null;
		
		// normalize the page content, set encoding&disposition
		var encoding = null, mime = null, disposition = "inline";
		if (this.is__encrypted(pi)) {
			ct = this.base64.encode_array(pages[pi]);
			encoding = "8bit/base64";
			// special header used for encrypted pages
			orig_len = pages[pi].length;
		} else {
			ct = pages[pi];
			if (this.is__embedded(pi)) {
				// if not forced to do them inline, convert for export
				var m;
				if (!inline_wsif) {
					disposition = "external";
					encoding = "8bit/plain";
					// decode the base64-encoded data
					if (this.is__image(pi)) {
						m = ct.match(this.wsif.reMimeMatch);
						record += this.wsif.header(pfx+"mime", m[1]);
						// remove the matched part
						ct = this.base64.decode(ct.substr(m[0].length));
					} else { // no data:uri for files
						ct = this.base64.decode(ct);
					}
				} else {
					encoding = "8bit/base64";
					if (this.is__image(pi)) {
						m = ct.match(this.wsif.reMimeMatch);
						if (m === null) {
							this.crash(page_titles[pi]+" is not a valid image!"+ct);							
							continue;
						} else {
							mime = m[1];
							// remove the matched part
							ct = ct.substr(m[0].length);
							m = null;
						}
						record += this.wsif.header(pfx+"mime", mime);
					}
				}
			} else { // normal wiki pages
				// check if ECMA encoding is necessary
				if (this.needs_ecma_encoding(ct)) {
					ct = this.ecma_encode(ct);
					encoding = "ecma/plain";
				} else
					encoding = "8bit/plain";
			}
		}
		//DEBUG check
		if (encoding === null) {
			this.crash("Encoding for page "+page_titles[pi]+" is set to null!");
			continue;
		}
		// update the index (if needed)
		if (!single_wsif && full_save) {
			full_wsif += this.wsif.header(pfx+"title", this.ecma_encode(page_titles[pi]));
			// a new mime type
			full_wsif += this.wsif.header(pfx+"encoding", "text/wsif");
			full_wsif += this.wsif.header(pfx+"disposition", "external");
			// add reference to the external WSIF file
			full_wsif += this.wsif.header(pfx+"disposition.filename", pi.toString()+".wsif")+
							"\n";
		}
		// update record
		if (!this.config.allow_diff)
			record += this.wsif.header(pfx+"length", ct.length);
		record += this.wsif.header(pfx+"encoding", encoding);
		record += this.wsif.header(pfx+"disposition", disposition);
		// note: when disposition is inline, encoding cannot be 8bit/plain for embedded/encrypted files
		if (disposition == "inline") {
			// output the original length header (if available)
			if (orig_len !== null)
				record += this.wsif.header(pfx+"original_length", orig_len);
			// create the inline page
			boundary = this.wsif._generate_random_boundary(boundary, ct);
			record += this.wsif.header(pfx+"boundary", boundary);
			// add the inline content
			record += this.wsif.inline(boundary, ct); ct = null;
		} else {
			// create the blob filename
			var blob_fn = "blob" + pi.toString() + woas._file_ext(page_titles[pi]);
			// specify path to external filename
			record += this.wsif.header(pfx+"disposition.filename", blob_fn)+"\n";
			// export the blob
			if (!this.save_file(path + blob_fn,
							(encoding === "8bit/plain") ?
							this.file_mode.BINARY : this.file_mode.ASCII_TEXT, ct))
				woas.log("Could not save "+blob_fn);	//log:1
			// release any lock held previously
			if (locking)
				this.lock.release(path+blob_fn);
		}
		// the page record is now ready, proceed to save
		if (single_wsif) {// append to main page record
			full_wsif += record;
			++done;
		} else { // save each page separately
			if (this.save_file(path+pi.toString()+".wsif",
								this.file_mode.ASCII_TEXT,
								// also add the pages counter (single)
								extra + this.wsif.header("woas.pages", 1) +
								"\n" + record))
				++done;
		}
		this.progress_status(done/l);
		// reset the record
		record = "";
	} // foreach page
	if (!single_wsif)
		extra += this.wsif.header('wsif.type', 'index'); // for safety in recursive loading
	// add the total pages number
	if (full_save || single_wsif)
		extra += this.wsif.header('woas.pages', done);
	else
		extra += this.wsif.header('woas.pages', page_titles.length);
	// build (artificially) an index of all pages
	if (!full_save && !single_wsif) {
		for (pi=0,pl=page_titles.length;pi<pl;++pi) {
			full_wsif += this.wsif.header(pfx+"title", this.ecma_encode(page_titles[pi]));
			// a new mime type
			full_wsif += this.wsif.header(pfx+"encoding", "text/wsif");
			full_wsif += this.wsif.header(pfx+"disposition", "external");
			// add reference to the external WSIF file
			full_wsif += this.wsif.header(pfx+"disposition.filename", pi.toString()+".wsif")+
							"\n";
		}
	}
	// output the index WSIF file now
/**
PVHL: need to quickly fix (with minimal side-effects) a really bad bug in saving to a bad data source.
if done == 0 here then there has been a failure in saving; blob failure will pass though -- this is
a separate bug that needs to be fixed as well; I am not addressing that bug at this time.
So: if !done don't save index. return value of 0 signals save failed; this is used to stop a save
of the html file -- otherwise a bad data source save wipes out the wiki.
*/
	if (done && !this.save_file(path+src_fname,
						this.file_mode.ASCII_TEXT,
						extra + "\n" + full_wsif)) {
		//if (single_wsif) - needs to be for any save type; signals error
			done = 0;
	} // we do not increment page counter when saving index.wsif
	
	// release any lock held previously
	if (locking)
		this.lock.release(path+src_fname);
	
	this.progress_finish();
	return done; // PVHL: if 0 save failed
};

woas._wsif_ds_load = function(subpath, locking) {
	// we reset the arrays before loading the real data from index.wsif
	pages = [];
	page_attrs = [];
	page_titles = [];
	page_mts = [];
	// get the data
	return this._native_wsif_load(woas.ROOT_DIRECTORY+subpath, locking, true, 0,
			this.importer._inject_import_hook);
};

/* description of parameters:
 - path: WSIF file path which will be loaded, can be null to use file specified in '_filename' element
 - locking: resource locking (not yet implemented)
 - _native: true when WoaS is in native mode (private use only)
 - recursing: recursion depth variable, starts with 0
 - import_hook: callback used to actually import the page
 - title_filter_hook: callback used to choose if page can be imported or not by title - optional
 - finalization_hook: callback used when import is finished
*/
woas._native_wsif_load = function(path, locking, _native, recursing, import_hook,
								title_filter_hook, finalization_hook) {
	var ct, is_index = false;
	if (!recursing) {
		this.wsif.emsg = null;
		this.progress_init("Initializing WSIF import");
	}
	// allow remote loading when running in native WSIF mode
	if (this._server_mode && (this.config.wsif_ds.length !== 0))
		ct = this.remote_load(path);
	else
		ct = this.load_file(path, this.file_mode.ASCII_TEXT);
	if (typeof ct != "string") {
		if (!recursing)
			this.progress_finish();
		if (ct === false)
			this.alert(this.i18n.LOAD_ERR);
		return false;
	}
	// PVHL: remove filename from path to allow loading of indexed pages
	if (path) {
		var pos = path.lastIndexOf('/') + 1 || path.lastIndexOf('\\') + 1;
		if (pos) path = path.substring(0, pos);
	}
	// reset when not recursing
	if (!recursing) {
		this.wsif.expected_pages = null;
		this.wsif.emsg = this.i18n.NO_ERROR;
		this.wsif.imported = [];
		this.wsif.global_progress = 0;
		this.wsif.generator = { version: null, name: null };
	}
	var pfx = "\nwoas.page.", pfx_len = pfx.length;
	// start looping to find each page
	var p = ct.indexOf(pfx), fail = false,
	// this is used to mark end-of-block
		previous_h = null, chk;

	// too early failure
	if (p === -1)
		this.wsif.do_error("Invalid WSIF file");
	else { // OK, first page was located
		// PVHL: check that contents has UNIX line endings
		//   (a handwritten wsif file could choke otherwise)
		chk = ct.substr(0, p);
		if (chk.indexOf('\r') !== -1) {
			// change to UNIX line endings
			ct = ct.replace(new RegExp("\r\n", "g"), "\n");
			p = ct.indexOf(pfx);
		}
		chk = null;

		// now get some general WSIF info
		var wsif_v = ct.substring(0,p).match(/^wsif\.version:\s+(.+)$/m);
		if (wsif_v === null) {
			this.wsif.do_error(this.i18n.WSIF_NO_VER);
			p = -1;
			fail = true;
		} else {
			// convert to a number
			wsif_v = wsif_v[1];
			var wsif_v_n = this._normver(wsif_v);
			// check if WSIF is from future of it is the unsupported 1.0.0
			if ((wsif_v_n == 100) || (wsif_v_n > this._normver(this.wsif.version))) {
				this.wsif.do_error(this.i18n.WSIF_NS_VER.sprintf(wsif_v));
				p = -1;
				fail = true;
			} else {
				if (!recursing) {
					// PVHL: added 'wsif.type: index' to allow safe recursion
					is_index = ct.substring(0, p).indexOf('wsif.type: index') !== -1;
					// PVHL: automatically set multi_file mode to prevent index file
					// corruption on save; this can be overridden in options, allowing
					// simple conversion to single-file.
					if (is_index) this.wsif.ds_multi = true;
					// get number of expected pages
					this.wsif.expected_pages = ct.substring(0,p).match(/^woas\.pages:\s+(\d+)$/m);
					if (this.wsif.expected_pages !== null)
						this.wsif.expected_pages = Number(this.wsif.expected_pages[1]);
					// gather generator information
					this.wsif.generator.name = ct.substring(0,p).
						match(/^wsif\.generator:\s+(.+)$/m);
					if (this.wsif.generator.name !== null) {
						this.wsif.generator.name = this.wsif.generator.name[1];
						this.wsif.generator.version = ct.substring(0,p).
							match((wsif_v_n < 131) ? /^woas\.version:\s+(.+)$/m : /^wsif\.generator\.version:\s+(.+)$/m);
						if (this.wsif.generator.version !== null) {
							this.wsif.generator.version = this.wsif.generator.version[1];
						}
					}

					// was generator information truly necessary?
					if (this.wsif.generator.name === "woas") {
						if (this.wsif.generator.version === null) {
							this.wsif.do_error("WSIF generator version is not available");
							p = -1;
							fail = true;
						} else {
							if (!_native)
								// copy to importer module
								this.importer._old_version = this._normver(this.wsif.generator.version);
							else { // native mode
								if (this.wsif.generator.version !== this.version) {
									this.wsif.do_error("WSIF generator version should match WoaS version");
									p = -1;
									fail = true;
								}
							}
						}
					} else {
						if (!_native) {
							// assume that any content generated with libwsif is up-to-date for import
							this.importer._old_version = this._normver(this.version);
						} else { // native mode
							this.wsif.do_error("WSIF generator is not 'woas'");
							p = -1;
							fail = true;
						}
					}

				} // !recursing
			} // valid version
		} // has version
	}
	var title = null,	attrs = null,
		last_mod = null,	len = null,
		encoding = null,	disposition = null,
		d_fn = null,	boundary = null,	mime = null;
	// position of last header end-of-line
	var sep, s, v, last_offset;
	while (p !== -1) {
		// save last entry offset, used by page definition
		last_offset = p;
		// remove prefix
		sep = ct.indexOf(":", p+pfx_len);
		if (sep === -1) {
			this.wsif.do_error(this.i18n.WSIF_NO_HN);
			fail = true;
			break;
		}
		// get attribute name
		s = ct.substring(p+pfx_len, sep);
		// get value
		p = ct.indexOf("\n", sep+1);
		if (p == -1) {
			this.wsif.do_error(this.i18n.WSIF_BAD_HV);
			fail = true;
			break;
		}
		// all headers except the title header can mark an end-of-block
		// the end-of-block is used to find boundaries and content inside
		// them
		if (s != "title")
			// save the last header position
			previous_h = p;
		// get value and apply left-trim
		v = ct.substring(sep+1, p).replace(/^\s*/, '');
		switch (s) {
			case "title":
				// we have just jumped over a page definition
				if (title !== null) {
					// do not import special/reserved pages
					var skip_page;
					if (typeof title_filter_hook == "function")
						skip_page = !title_filter_hook(title);
					else skip_page = false;
					if (skip_page) {
						title = attrs = last_mod = encoding = len =
							 boundary = disposition = mime = d_fn = null;
					} else {
						// store the previously parsed page definition
						var rv = this._native_page_def(path,ct,
								previous_h, last_offset,	// offsets to grab the page content
								import_hook,
								title,attrs,last_mod,len,encoding,disposition,
								d_fn,boundary,mime,locking,_native,title_filter_hook,is_index);
						// save page index for later analysis
						var was_title = title;
						title = attrs = last_mod = encoding = len =
							 boundary = disposition = mime = d_fn = null;
						if (!rv) // show a message but continue parsing
							woas.log("Import failure for "+was_title); //log:1
					}
					// delete the whole entry to free up memory to GC
					// will delete also the last read header (p != last_offset)
					ct = ct.substr(p);
					last_offset = p = 0;
					previous_h = null;
					// update status if not recursing
					if (!recursing && (this.wsif.expected_pages !== null))
						this.progress_status(this.wsif.global_progress++/this.wsif.expected_pages);
				}
				// let's start with the next page
				title = this.ecma_decode(v);
			break;
			case "attributes":
				attrs = Number(v);
			break;
			case "last_modified":
				if (this.config.store_mts)
					last_mod = Number(v);
			break;
			case "length":
				len = Number(v);
			break;
			case "encoding":
				encoding = v;
			break;
			case "disposition":
				disposition = v;
			break;
			case "disposition.filename":
				//TODO: ecma-escape
				d_fn = v;
			break;
			case "boundary":
				boundary = v;
			break;
			case "mime":
				mime = v;
			break;
			case "original_length":
				// this should be used for trimming base64 encrypted pages
				// ignored for now
			break;
			default:
				woas.log("Unknown WSIF header: "+s);	//log:1
		} // end switch(s)
		if (fail)
			break;
		// set pointer to next entry
		p = ct.indexOf(pfx, p);
	}
	if (fail) {
		if (!recursing)
			this.progress_finish();
		return false;
	}
	// process the last page (if any)
	if ((previous_h !== null) && (title !== null)) {
		var skip_page;
		if (typeof title_filter_hook == "function")
			skip_page = !title_filter_hook(title);
		else skip_page = false;
		if (!skip_page) {
			var rv = this._native_page_def(path,ct,previous_h,last_offset,
					import_hook,
					title,attrs,last_mod,len,encoding,disposition,
					d_fn,boundary,mime,locking,_native,title_filter_hook,is_index);
			// save page index for later analysis
			if (!rv)
				this.wsif.do_error( "Import error for page "+title+" after import!" );
			// update status if not recursing
			if (!recursing && (this.wsif.expected_pages !== null))
				this.progress_status(this.wsif.global_progress++/this.wsif.expected_pages);
		}
	}
	if (!recursing) {
		this.progress_finish();
		// call the finalization callback (if any)
		if (typeof finalization_hook == "function")
			finalization_hook();
	}
	// return total imported pages
	return this.wsif.imported.length;
};

// returns true if a page was defined, and save it in wsif.imported array
woas._native_page_def = function(path,ct,p,last_p,import_hook,
								title,attrs,last_mod,len,encoding,disposition,d_fn,boundary,mime,locking,_native,title_filter_hook, is_index) {
	var bpos_e, page;
	// attributes must be defined unless importing an exported multifile index.wsif
	if (attrs === null && !(disposition === "external" && encoding === "text/wsif")) {
		woas.log("No attributes defined for page "+title);	//log:1
		return false;
	}
	// disposition must be defined
	if (disposition === null) {
		woas.log("No disposition defined for page \""+title+"\"");	//log:1
		return false;
	}
	// last modified timestamp can be omitted
	if (last_mod === null)
		last_mod = 0;
		
	switch (disposition) {
		case "inline":
		// craft the exact boundary match string
		boundary = "\n--"+boundary+"\n";
		// locate start and ending boundaries
		var bpos_s = ct.indexOf(boundary, p);
		if (bpos_s == -1) {
			this.wsif.do_error( "Failed to find start boundary "+boundary+" for page "+title );
			return false;
		}
		bpos_e = ct.indexOf(boundary, bpos_s+boundary.length);
		if (bpos_e == -1) {
			this.wsif.do_error( "Failed to find end boundary "+boundary+" for page "+title );
			return false;
		}
		// retrieve full page content
		page = ct.substring(bpos_s+boundary.length, bpos_e);
		// length used to check correctness of data segments
		var check_len = page.length;
		// split encrypted pages into byte arrays
		if (attrs & 2) {
			if (encoding != "8bit/base64") {
				woas.log("Encrypted page "+title+" is not encoded as 8bit/base64");	//log:1
				return false;
			}
//			check_len = page.length;
			page = this.base64.decode_array(page);
			// trim to correct length
			// perhaps we could use woas.page.original_length field
			// also, we could not make this check if version is 0.10.4
			// but for now it's a good safety
			var rest = page.length % 16;
			if (rest)
				woas.log("NOTICE: removing "+rest+" trailing bytes from page "+title); //log:1
			while (rest-- > 0) {page.pop();}
		} else if (attrs & 8) { // embedded image, not encrypted
			// NOTE: encrypted images are not obviously processed, as per previous 'if'
			if (encoding != "8bit/base64") {
				woas.log("Image "+title+" is not encoded as 8bit/base64");	//log:1
				return false;
			}
			if (mime === null) {
				woas.log("Image "+title+"has no mime type defined");		//log:1
				return false;
			}
			// re-add data:uri to images
			page = "data:"+mime+";base64,"+page;
		} else { // a normal wiki page
			switch (encoding) {
				case "8bit/base64":
					// base64 files will stay encoded
					if (!(attrs & 4))
						// WoaS does not encode pages normally, but this is supported by WSIF format
						page = this.base64.decode(page);
				break;
				case "ecma/plain":
					page = this.ecma_decode(page);
				break;
				case "8bit/plain": // plain wiki pages are supported
				break;
				default:
					woas.log("Normal page "+title+" comes with unknown encoding "+encoding);	//log:1
					return false;
			}
		}
		// check length (if any were passed)
		if (len !== null) {
			if (len != check_len)
				// show a simple log message
				woas.log("Length mismatch for page %s: ought to be %d but was %d".sprintf(title, len, check_len)); //log:1
		}
		// fallback wanted to go to define the page
	break;
	case "external":	// import an external WSIF file
		if (d_fn === null) {
			this.wsif.do_error( "Page "+title+" is external but no filename was specified");
			return false;
		}
		// use filename from file input control to get path
		// PVHL: should not be here - always pass path in
		//	 What if it is erased during import?
		if (path === null) {
			path = this._get_path("filename_");
			if (!path) {
				this.wsif.do_error( "Could not retrieve path for external file");
				return false;
			}
		}
		else if (!(is_index || mime)) {
			this.wsif.do_error( "Recursive WSIF import only allowed for index and blob files");
			return false;
		}

		// embedded image/file, not encrypted
		if ((attrs & 4) || (attrs & 8)) {
			if (encoding !== "8bit/plain") {
				this.wsif.do_error( "Page "+title+" is an external file/image but not encoded as 8bit/plain");
				return false;
			}
			// load file and apply base64 encoding if embedded
			var wanted_mode;
			// images
			if ((attrs & 4) && (attrs & 8))
				wanted_mode = this.file_mode.DATA_URI;
			// files
			else if (attrs & 4)
				wanted_mode = this.file_mode.BASE64;
			else // dunnowhat
				wanted_mode = this.file_mode.BINARY;
			page = this.load_file(path+d_fn, wanted_mode, mime);
			if (typeof page != "string") {
				this.wsif.do_error( "Failed load of external "+path+d_fn);
				return false;
			}
			// fallback wanted to apply real page definition later
		} else {
			if (encoding != "text/wsif") {
				this.wsif.do_error( "Page "+title+" is external but not encoded as text/wsif");
				return false;
			}
			// check the result of external import
			var rv = this._native_wsif_load(path+d_fn, locking, _native,
											1, import_hook, title_filter_hook);
			if (rv === false)
				this.wsif.do_error( "Failed import of external "+path+d_fn);
			// return pointer after last read header
			return rv;
		}
	break;
	default: // no disposition or unknown disposition
		this.wsif.do_error( "Page "+title+" has invalid disposition: "+disposition);
		return false;
	} // end of switch

	// create the page object
	var NP = { "title": title, "attrs": attrs, "body": page, "mts": last_mod };
	
	// check that this was imported successfully
	if (import_hook( NP ) ) {
		// all OK
		this.wsif.imported.push(NP.i);
		return true;
	}

	return false;
};

/*** src/legacy.js ***/
// deprecated/legacy functions

// All the functions in this file are still supported but deprecated.
// They will be removed from WoaS before version 1.0

// var log = woas.log; set by woas._set_debug

d$.clone = function(o) {
	woas.log("WARNING: Called deprecated function: d$.clone (now woas.clone)");
	woas.clone(o);
};
function bool2chk(b) {
	woas.log("WARNING: Called deprecated function: bool2chk (now woas.bool2chk)");
	woas.bool2chk(b);
}
function _set_layout(fixed) {
	woas.log("WARNING: Called deprecated function: _set_layout (now woas.ui.set_layout)");
	woas.ui.set_layout(fixed);
}
function home() {
	woas.log("WARNING: Called deprecated function: home (now woas.ui.home)");
	woas.ui.home();
}
function help() {
	woas.log("WARNING: Called deprecated function: help (now woas.ui.help)");
	woas.ui.help();
}
function advanced() {
	woas.log("WARNING: Called deprecated function: advanced (now woas.ui.advanced)");
	woas.ui.advanced();
}
function go_to(t) {
	woas.log("WARNING: Called deprecated function: go_to (now woas.go_to(t))");
	return woas.go_to(t);
}
function go_back() {
	woas.log("WARNING: Called deprecated function: go_back (now woas.ui.back)");
	woas.ui.back();
}
function go_forward() {
	woas.log("WARNING: Called deprecated function: go_forward (now woas.ui.forward)");
	woas.ui.forward();
}
function edit() {
	woas.log("WARNING: Called deprecated function: edit (now woas.ui.edit)");
	woas.ui.edit();
}
function lock() {
	woas.log("WARNING: Called deprecated function: lock (now woas.ui.lock)");
	woas.ui.lock();
}
function unlock() {
	woas.log("WARNING: Called deprecated function: unlock (now woas.ui.unlock)");
	woas.ui.unlock();
}
function save() {
	woas.log("WARNING: Called deprecated function: save (now woas.save)");
	woas.save();
}
// old tables parsing syntax
woas.parser.reReapTables = /^\{\|.*((?:\n\|.*)*)$/gm;
woas.parser.reReapTableRows = /\n\|([+ -])(.*)/g;
woas.parser.parse_tables =  function (str, p1) {
	var caption = false,
		stk = [];
	p1.replace(woas.parser.reReapTableRows, function(str, pp1, pp2) {
			if (pp1 == '-')
				return;
			else if (pp1 == '+') {
				caption = caption || pp2;
				return;
			}
			stk.push('<'+'td>' + pp2.split('||').join('<'+'/td><'+'td>') + '<'+'/td>');
		} 
	);
	if (stk.length)
		return  '<' + 'table class="woas_text_area">' + (caption?('<' + 'caption>' + caption +
			'<' + '/caption>'):'') + '<' + 'tr>' + stk.join('<' + '/tr><' + 'tr>') + '<' +
			'/tr>' + '<' + '/table>' + woas.parser.NL_MARKER;
	return str;
};
woas.refresh_menu_area = function() {
	woas.log("WARNING: Called deprecated function: woas.refresh_menu_area (now woas.ui.refresh_menu)");
	this.ui.refresh_menu();
}

/*** src/ui.js ***/
// @module ui
// User Interface bindings
woas.ui = {
	edit_mode: false,		// set to true when inside an edit textarea
	_textbox_focus: false,	// true when a text box is currently focused
	focus_textbox: function() { // called when a textbox has currently focus
		// 'this' belongs to the text box
		woas.ui._textbox_focus = true;
	},
	blur_textbox: function() { // called when a textbox looses focus
		// 'this' belongs to the text box
		woas.ui._textbox_focus = false;
		ff_fix_focus();
		// reset event handler
		this._textbox_enter_event = this._textbox_enter_event_dummy;
	},
	// event (to be overriden) to run in case of enter key pressed
	// for example, searching
	_textbox_enter_event_dummy: function() {
	},
	_textbox_enter_event: null,
	// custom event handler which can be overriden to process the keypresses
	_custom_key_hook: function(orig_e) {
		// continue parsing as normal
		return true;
	},
	
	// event called on key press
	//NOTE: since this is attached directly to DOM, you should not use 'this'
/*
PVHL: FIX; this needs to be changed as
 1. every user page that adds a text input control needs to know about setting
    blur/focus textbox or else pressing backspace goes back a page.
 2. (comment belongs in hotkey code) deleting a custom key (like back/escape)
    does not remove it from access keys. User desires need to be recognized.
*/
	_keyboard_event_hook: function(orig_e) {
		var e = orig_e || window.event,
			ck = e.keyCode || e.which;
		if (!woas.ui.edit_mode) {
			// there is a custom focus active, call the hook
			// and return if it told us to do so
			if (!woas.ui._custom_key_hook(orig_e))
				return orig_e;
			if (woas.ui._textbox_focus) {
				// return key
				if (ck == 13) {
					// clear focus
					ff_fix_focus();
					// run attached event
					(woas.ui._textbox_enter_event)();
					return false;
				}
				return orig_e;
			}
			// back or cancel keys
			if ((ck == woas.hotkey.all.back) || (ck == woas.hotkey.all.cancel)) {
				woas.ui.back();
				ff_fix_focus();
				return false;
			}
		} else if (ck == woas.hotkey.all.cancel) {
			// cancel key in edit mode
			woas.ui.cancel();
			ff_fix_focus();
			return false;
		}
		return orig_e;
	},
	//  PVHL: This function now sends help system just the help page name
	//  (everything after WoaS::Help)
	help: function() {
		var pg;
		// we are editing
		if (this.edit_mode) {
			pg = "Editor";
		} else {
			// normalize namespace listings
			pg = current;
			if (pg.lastIndexOf('::') === pg.length - 2) {
				pg = pg.substring(0, pg.length - 2);
			}
			if (pg.indexOf('WoaS::') === 0 &&
					woas.help_system._help_lookup.indexOf(pg.substr(6)) !== -1) {
				// change the target page in some special cases
				pg = pg.substr(6);
			}
		}
		woas.help_system.go_to([pg, '']);
	},
	tables_help: function() {
		woas.help_system.go_to(["Tables", '']);
	},
	clear_search: function(no_render) {
//		woas.log("Clearing search"); //log:0
		if (current === "Special::Search") {
			d$("string_to_search").value = "";
			d$("string_to_search").focus();
		}
		// clear search results
		woas._cached_body_search = [];
		woas._cached_title_search = [];
		woas._last_search = null;
		woas.pager.bucket.clear();
		if (!no_render)
			this._search_render();
	},
	// when user clicks the about link
	about: function() {
		if (!this.edit_mode)
			woas.go_to("Special::About");
	},
	_search_render: function() {
		// render search results
		if (current === "Special::Search") {
			woas._search_load();
		} else // will call _search_load() on its own
			woas.go_to("Special::Search");
	},
	// wsif: for Special::Import false, Special::ImportWSIF true
	_import_load: function(wsif) {
		var except = wsif ? 3 : 0, i, settings, chk;
		if (!woas.config.permit_edits)
			d$("btn_import").disabled = true;
		// restore default settings - with some exceptions
		settings = wsif ? woas.config.import_wsif : woas.config.import_woas;
		for(i=0;i < woas.importer._settings_props.length-except;++i) {
			chk = woas.bitfield.get(settings, i);
			d$("woas_cb_import"+woas.importer._settings_props[i].substr(1))
				.checked = chk
			woas.importer[woas.importer._settings_props[i]] = chk;
		}
		if (wsif) {
			// these options are not available for WSIF
			woas.importer.i_styles = woas.importer.i_content = true;
			woas.importer.i_config = false;
		} else {
			// disable settings if needed by content setting
			this._import_load_change();
		}
		// restore the overwrite option which covers other 2 bits
		var ovr = 0;
		if (woas.bitfield.get(settings, woas.importer._OVR_ID))
			ovr += 1;
		if (woas.bitfield.get(settings, woas.importer._OVR_ID+1))
			ovr += 2;
		var params = ["erase", "ignore", "overwrite", "ask"];
		// apply parameter
		d$('woas_import_'+params[ovr]).checked = true;
		woas.importer.i_overwrite = ovr;
	},
	// WoaS::Import can disable page/css import
	// PVHL: TODO: make _import_load cache dom elements or make more efficient
	_import_load_change: function() {
		var c = woas.importer.i_content = d$("woas_cb_import_content").checked,
			s = woas.importer.i_styles = d$("woas_cb_import_styles").checked;
		// the IDs below are from parser.heading_anchor to allow use in links
		// MUST be changed if section title changed
		if (c || s) {
			d$.show("S10522");
		} else {
			d$.hide("S10522");
		}
		if (c) {
			d$.show("S4030");
		} else {
			d$.hide("S4030");
		}
	},
	// click on edit icon
	edit: function() {
		if (!this.display('no_edit')) {
			woas.edit_page(current);
		}
	},
	cancel: function() {
		if (!this.edit_mode)
			return;
		// there was some change, ask for confirm before cancelling
		if ((woas.get_raw_content() !== woas.change_buffer) ||
			(woas.trim(d$("wiki_page_title").value) !== woas.old_title)) {
			if (!confirm(woas.i18n.CANCEL_EDITING))
				return;
		}
		// we will cancel the creation of last page
		if (woas._ghost_page) {
			// we assume that the last page is the ghost page
			pages.pop();
			page_mts.pop();
			page_titles.pop();
			page_attrs.pop();
			// menu entry may have been added for cancelled new page
			var menu_i = woas.page_index("::Menu");
			if (menu_i !== -1) {
				// try to remove menu link
				var menu_orig = woas.get__text(menu_i);
				var menu = menu_orig.replace("\n[["+current+"]]", "");
				if (menu !== menu_orig) {
					woas.set__text(menu_i, menu);
					woas.ui.refresh_menu();
				}
			}
		}
		current = woas.prev_title;
		woas.update_view();
		woas.disable_edit();
	},
	// when back button is clicked
	back: function() {
		if (this.edit_mode || this.display('no_back')) {
			return false;
		}
		var p = woas.history.back();
		return p === null ? false : woas.set_current(p, true);
	},
	// when Forward button is clicked
	forward: function() {
		if (this.display('no_fwd')) {
			return false;
		}
		var p = woas.history.forward();
		return p === null ? false : woas.set_current(p, true)
	},
	// when home is clicked
	home: function() {
		if (!this.display('no_home')) {
			woas.go_to(woas.config.main_page);
		}
		
	},
	edit_menu: function() {
		var ns = woas.current_namespace, mpi, tmp;
		do {
			mpi = woas.page_index(ns + "::Menu");
			if (mpi !== -1) {
				woas.edit_page(ns + "::Menu");
				break;
			}
			tmp = ns.lastIndexOf("::");
			ns = tmp === -1 ? "" : ns.substring(0, tmp);
		} while (ns !== "");
	},
	lock: function() {
		if (!this.display('no_lock')) {
			if (woas.pager.bucket.items.length>1)
				// option not implemented
				_lock_pages(woas.pager.bucket.items);
			else
				woas.set_current("Lock::" + current, true, true);
		}
	},
	unlock: function() {
		if (!this.display('no_unlock')) {
			if (woas.pager.bucket.items.length>1)
				_unlock_pages(woas.pager.bucket.items);
			else
				woas.set_current("Unlock::" + current, true);
		}
	},
	// scroll to top of page
	top: function() {
		if (this.edit_mode) {
			d$('woas_editor').scrollTop = 0;
		} else {
			//scroll(0,0);
		document.documentElement.scrollTop = 0;
		document.body.scrollTop = 0;
		}
	},
	advanced: function() {
		if (!this.display('no_tools')) {
			woas.go_to("Special::Advanced");
		}
	},
	set_header: function(fixed) {
		if (!woas.browser.ie6) {
			//d$("woas_header_wrap").style.position = (fixed ? "fixed" : "absolute");
			this.display({fix_h: fixed}, true);
		}
	},
	set_menu: function(fixed) {
		if (!woas.browser.ie6) {
			//d$("woas_menu_wrap").style.position = (fixed ? "fixed" : "absolute");
			this.display({fix_m: fixed}, true);
		}
	},
	set_layout: function(fixed)  {
		this.set_header(fixed);
		this.set_menu(fixed);
	},
	toggle_debug: function() {
		if (!this.display('no_debug')) {
			d$.toggle_cls('no_log', true);
		}
	},
	// Used by Special::Options page (also used to check/repair filename in ExportWSIF)
	// chk_box & set are optional
	//
	// 1. if called with 'txt_box' & 'chk_box', and 'set' is true then may set config in
	//      UNIX format and save file -- only to be called from Special::Options code
	// 2. if called with 'txt_box', 'chk_box' only then sets elements with correct values
	// 3. if called with 'txt_box' alone then checks/repairs relative filename in txt_box
	//    (used by Special::ExportWSIF)
	wsif_ds: function(txt_box, chk_box, set) {
		// get path in UNIX format and trim; stored this way - but just to be safe
		var fn = woas.trim(txt_box.value.replace(/\\/g, '/')),
			ds = woas.trim(woas.config.wsif_ds.replace(/\\/g, '/')),
			str = '', i;
		// make sure path is relative - assume stored value is
		while (fn[0] === '/') fn = fn.substr(1);
		if ( set && (ds || fn) ) {
			i = woas.i18n;
			// 1. change data source settings and save file
			// create prompt string (truth table logic used; if str created
			// then a valid condition exists; otherwise reset options)
			if ( !( ds === fn && woas.wsif.ds_multi === this.wsif_ds_multi ) ) {
				if ( ds && !fn ) {
					str = i.WSIF_DS_TO_INTERNAL;
				} else if ( !ds && fn ) {
					str = i.WSIF_DS_TO_EXTERNAL + i.WSIF_EXIST;
				} else if (ds && fn && ds === fn) {
					if ( woas.wsif.ds_multi && !this.wsif_ds_multi ) {
						str = i.WSIF_DS_TO_SINGLE;
					} else if ( !woas.wsif.ds_multi && this.wsif_ds_multi ) {
						str = i.WSIF_DS_TO_MULTI;
					}
				}
				if ( ( ds && fn && ds !== fn ) ) {
					str += i.WSIF_EXIST;
				}
				if ( this.wsif_ds_multi && ( !ds || fn ) ) {
					str += i.WSIF_PAGES;
				}
			}
			// warn of potential risks before setting; restore original if needed
			if ( str && confirm(str + i.CHOOSE_CANCEL) ) {
				// update settings and save file
				woas.config.wsif_ds = fn; // save in UNIX format
				woas.wsif.ds_multi = fn && this.wsif_ds_multi;
				woas.full_commit();
				woas.set_current(current, true, true); // stop forward history destruction
			} else { // reset settings - approval not given or settings not valid
				fn = ds;
				this.wsif_ds_multi = woas.wsif.ds_multi;
				str = '';
			}
		}
		if (chk_box) {
			// 2. load correct values
			chk_box.checked = woas.bool2chk(woas.wsif.ds_multi);
			if (!set) {
				fn = ds;
			}
		}
		// 3. check/repair/set filename
		// convert unix path to windows path for display
		if (!str) {
			txt_box.value = is_windows ? fn.replace(reFwdSlash, '\\') : fn;
		}
	}
};

woas.ui._textbox_enter_event = woas.ui._textbox_enter_event_dummy;

//API1.0
// PVHL: should make go_to create history but not set_current; would make history easier
woas.go_to = function(cr) {
	var parts = cr.split('#'), section = parts[1], r = true, mv = 0, el;
	cr = parts[0];
	if (cr.indexOf(this.help_system._pfx) === 0 && cr.substr(-2) !== '::'
			&& current && page_titles.indexOf(parts[0]) !== -1) {
		// help system handles all help pages except WoaS::Help and namespace
		// listings unless loading wiki (current is empty)
		parts[0] = cr.substr(this.help_system._pfx.length);
		if (!parts[1]) {
			parts[1] = '';
		}
		woas.help_system.go_to(parts);
		return true;
	}
	// don't change page when editing or entering a password
	if (this.ui.edit_mode || this.ui.display('pswd')) {
		return false;
	}
	if (cr && cr !== current) {
			r = this.set_current(cr, true);
	}
	// PVHL: will rewrite this with dom caching once code stabilizes
	if (r && section) {
		el = d$(section);
		if (el) {
			mv = this.ui.display("fix_h")
				? el.offsetTop
				: el.offsetTop + d$("woas_header").offsetHeight;
		}
	}
	// there must be a better way!
	if (cr !== 'Special::Go to') {
		// Doing both doesn't hurt for now; need to do more testing.
		document.documentElement.scrollTop = mv; // IE up to 8; 9+?
		document.body.scrollTop = mv; // Chrome, FF, Opera; Safari? Probably
	}
	return r; // if loading could pass back scroll amount: current = ''
};

function back_or(or_page) {
	if (!woas.ui.back() && or_page !== current)
		woas.set_current(or_page, true);
}

// when cancel is clicked
function cancel() {
	woas.log("Called deprecated function: cancel");
	woas.ui.cancel();
}

// @module help_system
// PVHL: TODO close window in unload function
woas.help_system = {
	// page names that need to be modified for help lookup: WoaS:: +
	_help_lookup: ["Aliases", "CSS", "CSS::Boot", "CSS::Core", "CSS::Custom", "Hotkeys", "Plugins"],
	// make it easier to change names of help pages
	_pfx: "WoaS::Help::",
	popup_window: null,
	popup_wnd: ',status=no,menubar=no,resizable=yes,scrollbars=no,location=no,toolbar=no',
	// PVHL: TODO store values of these on resize in a config var - add top & left
	popup_w: Math.ceil(screen.width * 0.4),
	popup_h: Math.ceil(screen.height * 0.75),

	popup_code: woas.raw_js("\n\
function get_parent_woas() {\n\
	if (window.opener && !window.opener.closed)\n\
		return window.opener.woas;\n\
	else return null;\n\
}\n\
woas = {\n\
	go_to: function(pg) {\n\
		var woas = get_parent_woas();\n\
		if (woas !== null) {\n\
			// handle section-only links\n\
			if (pg.indexOf('#') === 0) {\n\
				woas.help_system.go_to(['', pg.substr(1)]);\n\
			}\n\
			woas.go_to(pg);\n\
		}\n\
	}\n\
}\n\
// used in help popups to access index\n\
function help_go_index() {\n\
	var woas = get_parent_woas();\n\
	if (woas !== null) {\n\
		woas.help_system.go_to(['Index', '']);\n\
	}\n\
}\n\
// used in help popups to go back to previous page\n\
function help_go_back() {\n\
	var woas = get_parent_woas();\n\
	if (woas !== null) {\n\
		woas.help_system.going_back = true;\n\
		woas.help_system.go_to([woas.help_system.previous_page.pop(), '']);\n\
	}\n\
}\n\
function d$(id) {\n\
	return document.getElementById(id);\n\
}\n\
function help_resize() {\n\
	var top = d$('woas_help_top_wrap').offsetHeight,\n\
		body = d$('woas_help_body_wrap');\n\
	body.style.top = top + 'px'; // stops a slight flash on some browsers\n\
	body.style.height = document.body.offsetHeight - top + 'px';\n\
}\n\
window.onresize = help_resize;\n"
	),

	// PVHL: this needs to be replaced with content from a page; too many side-effects
	//   to bother with right now; redesign coming in new version.
	// params: back|close value, back|close title, back|close function, display title, body
	popup_page: '<'+'div id="woas_help_top_wrap"><'+'div class="woas_help_top">\n\
<'+'input tabindex=2 class="woas_help_button" value="%s" title="%s" onclick="%s()"\
type="button" /><'+'input tabindex=1 class="woas_help_button" value="Index" onclick\
="help_go_index()" type="button" />%s<'+'/div><'+'/div><'+'div id="woas_help_body_wrap">\
<'+'div id="woas_help_body">\n%s<'+'/div><'+'/div>',

	going_back: false,
	previous_page: [],
	// PVHL: code changed to accept an array containing [page, section]
	//   - only comes here if a help page is targeted
	//   - page is name of help page without prefix
	//   - section must be a string (e.g. '')
	//   - no test has been done to see if help page exists
	go_to: function(pg) {
//		woas.log("help_system.go_to(["+pg.join('#')+"])");	//log:0
		if (!pg || pg.length !== 2 || !this.page_title && !pg[0]) {
			// add a log msg?
			this.going_back = false;
			pg = null;
			return;
		}
		if (pg[0]) {
			pg.push(woas.get_text(this._pfx + pg[0]));
			if (!pg[2]) {
				pg[2] = woas.get_text(this._pfx + 'Index');
				if (!pg[2]) { // add a log msg?
					this.going_back = false;
					pg = null;
					return;
				}
				pg[0] = 'Index';
			}
		}
		// save previous page and set new
		if (this.going_back) {
			this.going_back = false;
		} else if (this.page_title) {
			if (pg[0] !== this.page_title) {
				this.previous_page.push( this.page_title );
			} else if (!pg[1] && !this.popup_window.closed) {
				// same page and no section; just bring to front
				setTimeout('woas.help_system.popup_window.focus()', 0);
				return;
			}
		}
		if (pg[0]) {
			this.page_title = pg[0];
		}
		// allow overriding this function
		this.make_pop_up(pg);
/*
PVHL:
  any help page scripts are only active for main window (allows use of examples
  in main window). This works for now because Javascript code doesn't work the
  way the scripting module assumes: removing a script tag does NOT remove the
  code that tag created; the tag could be removed immediately after creation
  without affecting anything. Until scripting is rewritten to fix the clear
  function this activation is sufficient.
*/	
		woas.scripting.activate("page");
	},

	// PVHL: create a custom help page from scratch that works in all browsers
	//   pg = [title, section, text]; all must be strings
	make_pop_up: function(pg) {
		var title = this._pfx + pg[0], btn, fn, el;
		if ((this.popup_window === null) || this.popup_window.closed) {
			this.previous_page = [];
			this.popup_window = woas.popup("help_popup", this.popup_w,
				this.popup_h, this.popup_wnd,
				'<'+'title>' + title + '<'+'/title>' + '<'+'style type="text/css">'
				+ woas.css.get() + '<'+'/style>' + this.popup_code,
				woas.parser.parse(this.popup_page.sprintf(
					'Close', 'Close', 'window.close', pg[0], pg[2])),
				' class="woas_help"', ' class="woas_help"');
		} else { // load new page
			btn = this.previous_page.length ? 'Back' : 'Close';
			fn = this.previous_page.length ? 'help_go_back' : 'window.close';
			woas.setHTMLDiv(this.popup_window.document.body, woas.parser.parse(
					this.popup_page.sprintf(btn, btn, fn, pg[0], pg[2])));
			this.popup_window.document.title = title;
		}

		// in case popup is waiting for Javascript permission; seen on IE.
		if (this.popup_window.help_resize) {
			this.popup_window.help_resize();
			if (pg[1]) {
				el = this.popup_window.d$(pg[1]);
				if (el) {
					this.popup_window.d$("woas_help_body_wrap").scrollTop = el.offsetTop;
				}
			}
			// stop page load flash
			setTimeout('woas.help_system.popup_window.focus()', 0);
		}
		pg = null;
	}
};

function menu_dblclick() {
	if (!woas.config.dblclick_edit)
		return false;
	woas.ui.edit_menu();
	return true;
}

function page_dblclick() {
	if (!woas.config.dblclick_edit)
		return false;
	edit();
	return true;
}

/** Used by search box **/
function menu_do_search() {
	// directly use the search page if it is active
    if (current === "Special::Search") {
		d$('string_to_search').value = d$('menu_string_to_search').value;
    }
    woas.do_search(d$('menu_string_to_search').value);
}

// Used by Special::Search
// make the actual search and cache the results
function ssearch_do_search() {
	var search_string = d$("string_to_search").value;
	woas.do_search(search_string);
}

function menu_key_hook(orig_e) {
    var e;
    if (!orig_e)
        e = window.event;
    else
        e = orig_e;
	var ck = woas.browser.ie ? e.keyCode : e.which;
    if (ck == 13) {
		ff_fix_focus();
		menu_do_search();
        return false;
     }
     return orig_e;
}

//FIXME: this is entirely a bad hack
function menu_search_focus(f) {
	if (f) {
		// prevent focus on the menu search box when the search page is active
		if (current == "Special::Search") {
//		ff_fix_focus();
			d$('string_to_search').focus();
		} else {
			woas.ui.focus_textbox();
		}
	} else {
		if (current != "Special::Search")
			woas.ui.blur_textbox();
	}
}

//NOTE: this is attached to onkeydown of menu's search box, so you can't use 'this'
woas.do_search = function(str, noclear) {
	if (!str)
		return;
	// clear previous search results
	if (!noclear)
		woas.ui.clear_search(true);

	woas.progress_init("Searching");
	// reset result pages
	woas.pager.bucket.clear();

	// cache new search results
	woas._cache_search( str );
	woas.progress_finish();

	// refresh the search page, or go to it if we are not
	woas.ui._search_render();
};

// Used by Special::Options page
function save_options() {
	if (!woas.config.permit_edits) {
		alert(woas.i18n.READ_ONLY);
		return false;
	}
	woas.cfg_commit();
	// prefer to stay on the options page after saving
	woas.set_current(current, false);
}

function ro_woas() {
	if (!woas.config.permit_edits) {
		alert(woas.i18n.WRITE_PROTECTED);
		return false;
	}
	if (confirm(woas.i18n.CONFIRM_READ_ONLY + woas.i18n.CHOOSE_CANCEL)) {
		woas.config.permit_edits = false;
		woas.ui.display({ro:true}); // turn off icons
		woas.cfg_commit();
		// reloads page without killing forward history
		woas.set_current(current, true, true);
	}
}

// Used by Special::Lock
function lock_page(e) {
	// PVHL: see my notes for woas._password_ok for flag use discussion
	var flag = e ? e.keyCode === 13 : true, pw1, pw2;
	if (flag) {
		pw1 = d$("pw1");
		pw2 = d$("pw2");
		if (!woas.currently_locking || !pw1 || !pw2) {
			return;
		}
		if (!pw1.value.length) {
			pw1.focus();
			return;
		}
		if (!pw2.value.length) {
			pw2.focus();
			return;
		}
		if (pw1.value !== pw2.value) {
			alert(woas.i18n.PWD_ERROR);
			pw2.focus();
			return;
		}
		woas.AES.setKey(pw1.value);
		woas._finalize_lock(woas.page_index(woas.currently_locking), true);
	}
	return true;
}

// used in Special::Options
woas.bool2chk = function(b) {
	if (b) return "checked";
	return "";
}

// import wiki from external file
function import_wiki() {
	if (!woas.config.permit_edits) {
		alert(woas.i18n.READ_ONLY);
		return false;
	}
	woas.import_wiki();
}

function set_key() {
	woas._set_password();
}

// below function is used by Special::Lock

var _pw_q_lock = false;

function pw_quality() {
	if (_pw_q_lock)
		return;
	_pw_q_lock = true;

	// used to get a red-to-green color tone
	function _hex_col(tone) {
		var s=Math.floor(tone).toString(16);
		if (s.length==1)
			return "0"+s;
		return s;
	}

	// original code from http://lxr.mozilla.org/seamonkey/source/security/manager/pki/resources/content/password.js
	var pw=d$('pw1').value;

	//length of the password
	var pwlength=pw.length;
	
	if (pwlength!==0) {

	//use of numbers in the password
	  var numnumeric = pw.match(/[0-9]/g);
	  var numeric=(numnumeric!==null)?numnumeric.length/pwlength:0;

	//use of symbols in the password
	  var symbols = pw.match(/\W/g);
	  var numsymbols= (symbols!==null)?symbols.length/pwlength:0;

	//use of uppercase in the password
	  var numupper = pw.match(/[^A-Z]/g);
	  var upper=numupper!==null?numupper.length/pwlength:0;
	// end of modified code from Mozilla
	
	var numlower = pw.match(/[^a-z]/g);
	var lower = numlower!==null?numlower.length/pwlength:0;
	
	var u_lo = upper+lower;
	  
	// 80% of security defined by length (at least 16, best 22 chars), 10% by symbols, 5% by numeric presence and 5% by upper case presence
	var pwstrength = ((pwlength/18) * 65) + (numsymbols * 10 + u_lo*20 + numeric*5);
	
	var repco = woas.split_bytes(pw).toUnique().length/pwlength;
	if (repco < 0.8)
		pwstrength *= (repco+0.2);
//		woas.log("pwstrength = "+(pwstrength/100).toFixed(2)+", repco = "+repco);	// log:1
	} else
		pwstrength = 0;
  
	if (pwstrength>100)
		color = "#00FF00";
	else
		color = "#" + _hex_col((100-pwstrength)*255/100) + _hex_col((pwstrength*255)/100) + "00";
  
	d$("pw1").style.backgroundColor = color;
	woas.setHTMLDiv(d$("txtBits"), woas.i18n.PWD_KEY_SIZE.sprintf(pwlength*8));

	_pw_q_lock = false;
}

// used by embedded file show page
function show_full_file(pi) {
	var text = woas.get__text(pi);
	if (text===null)
		return;
	// put WoaS in loading mode
	woas.progress_init("Loading full file");
	// clear the partial display and put in the whole file content
	woas.setHTML(d$('_part_display'), '');
	woas.setHTML(d$('woas_file_ct'), woas.xhtml_encode(woas.base64.decode(text)));
	// finished loading the file
	woas.progress_finish();
}

function query_export_file(cr) {
	var fn = cr.substr(cr.indexOf("::")+2);
	if (confirm(woas.i18n.CONFIRM_EXPORT.sprintf(cr)+"\n\n"+woas.ROOT_DIRECTORY+fn))
		woas.export_file(cr, woas.ROOT_DIRECTORY+fn);
}

function query_export_image(cr) {
	var img_name = cr.substr(cr.indexOf("::")+2);
	if (confirm(woas.i18n.CONFIRM_EXPORT.sprintf(img_name)+"\n\n"+woas.ROOT_DIRECTORY+img_name))
		woas.export_image(cr, woas.ROOT_DIRECTORY+img_name);
	return false;
}


// PVHL: FIX Goes back 2 pages
function query_delete_file(cr) {
	if (!confirm(woas.i18n.CONFIRM_DELETE.sprintf(cr)))
		return;
	// do not check for plugin deletion here
	woas.delete_page(cr);
	return false;
}

// delayed function called after page loads and runs the script tag
// PVHL: this should be called by img onload event, not a timer
function _img_properties_show(mime, tot_len, enc_len, mts, fail) {
	var img ='woas_img_tag', html = '';
	if (fail) {
		html = woas.i18n.IMG_LOAD_ERR;
		d$.hide(img);
	} else {
		img = d$(img);
	}
	html +=	"\n"+woas.i18n.MIME_TYPE+": "+mime+"\n"+
		woas.i18n.FILE_SIZE+": about "+_convert_bytes(((tot_len-enc_len)*3)/4, 1)+
		woas.i18n.B64_REQ.sprintf(_convert_bytes(tot_len, 1))+
		"\n"+woas.last_modified(mts)+(fail ? ''
		: "\n"+woas.i18n.WIDTH+": "+img.width+"px\n"+
		woas.i18n.HEIGHT+": "+img.height+"px");
	woas.setHTMLDiv(d$('woas_img_desc'), woas.parser.parse(html));
	return false;
}

function query_delete_image(cr) {
	if (!confirm(woas.i18n.CONFIRM_DELETE_IMAGE.sprintf(cr)))
		return;
	// do not check for plugin deletion here
	woas.delete_page(cr);
	back_or(woas.config.main_page);
	return false;
}

// triggered by UI graphic button
// PVHL: print CSS now controlled by CSS (section /* PRINT */) to allow change
//   by those who use the print window for presentations.
//   Could use custom print css read from WoaS::CSS::Print instead
function page_print() {
	var t = "WoaS Print - " + current;
	if (!woas.popup_window || woas.popup_window.closed) {
		woas.popup_window = woas.popup(
			"woas_print_popup",
			Math.ceil(screen.width*0.75),
			Math.ceil(screen.height*0.75),
			",status=yes,menubar=yes,resizable=yes,scrollbars=yes",
			"<"+"title>" + t + "<"+"/title>" + "<"+"style type=\"text/css\">"+
				woas.css.get() + "<"+"/style>" +
				woas.raw_js('woas={};woas.go_to=function(page){alert("'+
					woas.js_encode(woas.i18n.PRINT_MODE_WARN)+'");}'),
			'<'+'h1 class="woas_print_title">'+current+'<'+'/h1>'+
				woas.getHTMLDiv(d$("woas_page")),
			' id="woas_page" class="woas_print"');
	} else {
		woas.setHTMLDiv(woas.popup_window.document.body,
			'<'+'h1 class="woas_print_title">'+current+'<'+'/h1>'+
			woas.getHTMLDiv(d$('woas_page')));
		woas.popup_window.document.title = t;
		//woas.popup_window.focus();
		setTimeout('woas.popup_window.focus()', 0);
	}
}

/*
This function is no longer used by the help system; print_popup is hardwired?
Also no longer used by the page_print function, but left here just in case it's
used by custom code (want print to be customizable)
*/
woas._customized_popup = function(page_title, page_body, additional_js,
		additional_css, body_extra) {
	if (additional_js.length)
		additional_js = woas.raw_js(additional_js);
	// create the popup
	return woas.popup(
		"print_popup",
		Math.ceil(screen.width*0.75),
		Math.ceil(screen.height*0.75),
		",status=yes,menubar=yes,resizable=yes,scrollbars=yes",
		// head
		"<"+"title>" + page_title + "<"+"/title>" + "<"+
		"style type=\"text/css\">"+ woas.css.get() + additional_css +
		"<"+"/sty" + "le>" + additional_js, page_body, body_extra
	);
};

// below functions used by Special::Export

// PVHL: blob saving disabled until it works cross-browser
woas.export_wiki_wsif = function () {
	var path, fname, author, single_wsif, inline_wsif, all_wsif, done, pos;
	try {
		path = d$("woas_ep_path").value;
		pos = path.lastIndexOf('/') + 1 || path.lastIndexOf('\\') + 1;
		if (pos) {
			fname = path.substring(pos);
			path = woas.ROOT_DIRECTORY + path.substring(0, pos);
		}  else {
			fname = path;
			path  = woas.ROOT_DIRECTORY;
		}
		author = this.trim(d$("woas_ep_author").value);
		single_wsif = !d$("woas_cb_multi_wsif").checked;
		//inline_wsif = !d$("woas_cb_linked_wsif").checked;
		inline_wsif = true;
		all_wsif = !!d$("woas_cb_all_wsif").checked;
	} catch (e) { this.crash(e); return false; }
	
	done = this._native_wsif_save(path, fname, false, single_wsif, inline_wsif, author, all_wsif, []);
	if (done) {
		this.alert(this.i18n.EXPORT_OK.sprintf(done, this.wsif.expected_pages));
	} else {
		this.alert(this.i18n.SAVE_ERROR.sprintf(fname));
	}
	return true;
};

// create a centered popup given some options
woas.popup = function(name,fw,fh,extra,head,body, body_extra, html_extra) {
	body_extra = body_extra || "";
	html_extra = html_extra || "";
	var hpos=Math.ceil((screen.width-fw)/2);
	var vpos=Math.ceil((screen.height-fh)/2);
	var wnd = window.open("about:blank",name,"width="+fw+",height="+fh+		
	",left="+hpos+",top="+vpos+extra);
	wnd.focus();
	wnd.document.writeln(this.DOCTYPE+"<"+"html"+html_extra+"><"+"head>"+head+
						"<"+"/head><"+"body"+body_extra+">"+
						body+"<"+"/body></"+"html>\n");
	wnd.document.close();
	return wnd;
};

// PVHL: None of the progress stuff works because JavaScript is single-threaded
// tell user how much work was already done
woas.progress_status = function (ratio) {
	// no progress indicators in debug mode
	if (this.config.debug_mode) return;
	this.setHTML(d$("woas_wait_text"), this._progress_section + "\n" +
				Math.ceil(ratio*100)+"% done");
};

// used to debug progress indicators
woas._progress_section = false;

// reset progress indicator
woas.progress_init = function(section) {
	if (this._progress_section !== false) {
		this.crash("Progress indicator already started for "+this._progress_section+
					", will not start a new one for "+section);
		return;
	}
	this._progress_section = section;
	if (typeof section == "undefined")
		section = "";
	else section = "\n" + section;
	// no progress indicators in debug mode
	if (this.config.debug_mode) return;
	this.setHTML(d$("woas_wait_text"), section);
	document.body.style.cursor = "wait";
	// put in busy mode and block interaction for a while
	this.ui.display({"wait": true});
	d$("loading_overlay").focus();
};

/*
PVHL: previously this did nothing if in debug mode and 'crashed' if it
  didn't know progress was being used. This can lead to problems from
  various sources. One issue was that if debug mode was changed by import
  then the cursor stayed in 'wait'. This now does the same for every
  caller - just in case; at worst we waste a little time. Cursor control
  will soon be handed over to CSS and '.woas_wait'; leave for now
*/
woas.progress_finish = function(section) {
	document.body.style.cursor = "auto";
	this.setHTML(d$("woas_wait_text"), this.i18n.LOADING);
	if (this.ui.display('wait')) {
		// hide the progress area
		this.ui.display({wait: false});
	}
	this._progress_section = false;
};

function search_focus(focused) {
	if (focused) {
		woas.ui._textbox_enter_event = ssearch_do_search;
		woas.ui.focus_textbox();
	} else {
		woas.ui.blur_textbox();
		ff_fix_focus();
	}
}

woas._hl_marker = _random_string(10)+":%d:";

woas._hl_marker_rx = new RegExp(woas._hl_marker+":(\\d+):", "g");

// display search results
woas._search_load = function() {
	woas.log("called _search_load()");
	var P = {body: ""};
	if (this._last_search === null) {
//		woas.log("No search done, returning blank");	//log:0
	} else {
		// proceed to parsing if there are matching pages
		if (this._cached_title_search.length + this._cached_body_search.length !== 0) {
		
			// (1) prepare the title results
			for(var i=0,it=this._cached_title_search.length;i<it;++i) {
				P.body += "* [["+ this._cached_title_search[i] + "]]\n";
				woas.pager.bucket.add(this._cached_title_search[i]);
			}
			
			// (2) parse the body snippets
			for(var i = 0, it = this._cached_body_search.length; i < it; ++i) {
				P.body += "\n* [[" + this._cached_body_search[i].title + "]] - found "
						+ this._hl_marker+":" + i + ":";
				woas.pager.bucket.add(this._cached_body_search[i].title);
			}

			P.body = 'Results for <'+'strong class="woas_search_highlight">'
					+ woas.xhtml_encode(woas._last_search) + "<"+"/strong>\n" + P.body;
		} else
			P.body = "/No results found for *" + woas.xhtml_encode(woas._last_search) + "*/";

	}

	// position cursor back in search box
	d$("string_to_search").focus();
	
	if (P.body.length) {
		// parse results before applying search terms highlighting
		woas.parser.syntax_parse( P, [] );
		
		P.body = P.body.replace(this._hl_marker_rx, function(str, i) {
			var r="",count=0;
			// PVHL: don't worry about IE pre as results are single line
			for(var a=0,at=woas._cached_body_search[i].matches.length;a<at;++a) {
				r += "<"+"pre class=\"woas_search_results\">" +
						// apply highlighting
						woas._cached_body_search[i].matches[a].replace(woas._reLastSearch, function(str, $1) {
							++count;
								return '<'+'span class="woas_search_highlight">'+$1+'<'+'/span>';
						})+"<"+"/pre>";
			}
			return " <"+"strong>"+count+"<"+"/strong> times: "+r;
		});
	}
	
	// finally output XHTML content
	woas.setHTMLDiv(d$('woas_search_results'), P.body);
};

var _servm_shown = false;

function _servm_alert() {
	if (woas._server_mode) {
		// show the message only once
		if (!_servm_shown) {
			woas.alert(woas.i18n.SERVER_MODE);
			_servm_shown = true;
		}
	}
}

woas.update_view = function() {
	var v = {view: true, edit: false};
	v.no_back = !this.history.has_backstack();
	v.no_fwd = !this.history.has_forstack();
	v.no_home = current === this.config.main_page;
	v.no_tools = current === "Special::Advanced";
	v.no_edit = !(this.config.permit_edits && this.edit_allowed(current));
	/* turn correct lock/unlock icons on/off then disable/enable them both */
	v.locked = this.is_encrypted(current);
	v.unlocked = !v.locked;
	v.no_lock = !this.config.permit_edits || this.is_reserved(current);
	this.ui.display(v, true);
};

// PVHL: this function not used by update_nav_icons (now update_view) any more as it
// had added functionality that is currently untested and unused.
// See 0.12.0 code (or my earlier code) for code
//
// woas.update_lock_icons = function(page) {

// when the page is resized
// PVHL: still some edit resize issues with Safari. Works well enough though.
//   document.documentElement.clientHeight works in all browsers so window.height
//   not used; old IEs don't have window.height.
//   Quickly refactored to handle long titles; will do better in new code
//   Top padding for content is hard-wired to 12px until I can test more browsers
woas.ui._resize = (function() {
	var hh = -1;
	function resize(p) {
		// hack to adjust header for two line titles
		var hh_el = d$("woas_header"), hh_now; // els should be cached
		if (hh_el) {
			// Opera is failing with offsetHeight
			hh_now = hh_el.offsetHeight;
			if (hh !== hh_now) {
				hh = hh_now;
				d$("woas_content").style.paddingTop = hh_now + 12 + "px";
			}
		}
		if (woas.ui.edit_mode) {
			// h - 1 helps early IE and Opera; not sure why yet; OK for others
			var e = d$('woas_editor'), h = e.offsetHeight +
				document.documentElement.clientHeight - document.body.offsetHeight - 1;
			if (woas.browser.ie && Number(woas.browser.ie) < 7) {
				// stops IE6 textarea overflow; will fix later
				e.style.width = 0;
				e.style.width = d$('woas_editor_sizer').offsetWidth + 'px';
			}
			e.style.height = (h > 64 ? h : 64) + 'px';
		}
	}
	return woas.browser.ie && Number(woas.browser.ie) < 8
		// stops ie6/7 editor resizing issue until good fix known
		? function() { setTimeout(resize, 0) }
		: function() { resize(); };
}());
window.onresize = woas.ui._resize;

woas._set_debug = function(status, closed) {
	var logbox = d$("woas_debug_log"), lines = -1, position = 0,
		cut = 100, max = 200; // cut > 0, max > cut
	if (status) {
	// logging function - used in development; call without argument to scroll to bottom
	// and see if we are in debug mode
		woas.log = function (msg) {
			if (msg) {
				if (!woas.tweak.integrity_test) {
					// log up to max lines; 'cut' lines removed if too big
					if (++lines === max) { // lines is line count now, before this post
						logbox.value = logbox.value.substring(position);
						lines = max - cut;
					} else if (lines === cut) {
						position = logbox.value.length;
					}
				}
				logbox.value += msg + '\n';
				// same msg to console
				if (window.console) {
					console.log(msg);
				// kept as it was here first
				} else if (window.opera) {
					opera.postError(msg);
				}
			}
			// keep the log scrolled down
			logbox.scrollTop = logbox.scrollHeight;
			return true;
		};
		// activate debug icon
		this.ui.display({no_debug: false, no_log: closed});
	} else {
		this.ui.display({no_debug: true, no_log: true});
		logbox.value = '';
		woas.log = function() { return false; };
	}
	// hide the progress area - PVHL: why done here?
	this.ui.display({wait: false});
	window.log = woas.log // for deprecated function - legacy.js
};

/*
PVHL:
  this function (was refresh_menu_area) now sets the menu using the highest
  namespace menu found for much greater flexibility and better looks.
  If people have problems with this I'll write an update plugin to put
  menu at beginning of sub-menu.
*/
woas.ui.refresh_menu = function() {
	var pi = -1, menu, ns, tmp;
	// locate the menu for current namespace, or a previous one if not found
	// (all the way back to ::Menu if need be). Menu is set every time, though
	// I will see if it makes sense not to for ns=''. There are issues with
	// this, though, and I had to disable optional loading in original code.
	// For now no special menus for any core pages - nice to have later.
	if (current.indexOf('WoaS::') === 0 || current.indexOf('Special') === 0) {
		tmp = -1;
	} else {
		tmp = current.lastIndexOf("::");
	}
	ns = tmp > 0 ? current.substr(0, tmp) : '';
	while (true) {
//		woas.log("menu testing "+ns+"::Menu");	// log:0
		pi = woas.page_index(ns+"::Menu");
		if (pi !== -1 || !ns) { break; }
		tmp = ns.lastIndexOf("::");
		ns = tmp === -1 ? "" : ns.substr(0, tmp);
	}
	menu = pi === -1 ? 'ERROR: No menu!' : woas.get__text(pi);
	if (menu) {
//		woas.log("menu found: "+page_titles[pi]);	// log:0
		woas.parser._parsing_menu = true;
		woas.setHTMLDiv(d$("woas_menu"),
			woas.parser.parse(menu, false, woas.js_mode(ns+"::Menu")));
		woas.parser._parsing_menu = false;
		if (!ns) {
// PVHL: check why this is done every time; change to when needed
			woas.scripting.clear("menu");
			woas.scripting.activate("menu");
		}
	} else {
		woas.setHTMLDiv(d$("woas_menu"), '');
		woas.scripting.clear("menu");
	}
	woas.current_namespace = ns;
};

// adapted by PVHL from: weston.ruter.net/2009/05/07/detecting-support-for-data-uris
woas.ui.img_display = function() {
	function loaded(el){ /*alert(el.width+" "+el.height);*/
		if (el.width !== 1 || el.height !== 1) {
			woas.ui.display({no_img: true});
		}
	}
	var data = new Image();
	data.onload = function() {/*alert("onload");*/loaded(this);}
	data.onerror = function() {/*alert("onerror");*/loaded(this);}
	data.src = "";
};

woas.menu_display = function(id, visible, opaque) {
	// toolbar images now controlled through anchor tag; dim instead of hiding
	i=id; id = d$('woas_' + id);
	opaque = opaque || false;
	var c = opaque ? 'woas_disabled' : 'woas_hide', ic = id.className, p = ic.indexOf(c);
	if (visible && p !== -1) {
		if (p) {
			id.className = ic.substr(0, ic[p - 1] === ' ' ? p - 1 : p) + ic.substr(p + c.length);
		} else {
			id.className = ic.substr(c.length + (ic.length > c.length && ic[c.length + 1] === ' ' ? 1 : 0));
		}
	} else if (!visible && p === -1) {
		id.className += (ic.length ? ' ' : '') + c;
	}
};

woas.refresh_mts = function(mts) {
	// generate the last modified string to append
	if (mts) {
		this.setHTMLDiv(d$("woas_mts"), this.last_modified(mts));
		this.ui.display({"no_mts": false});
	} else
		this.ui.display({"no_mts": true});
};

woas._set_title = function (new_title) {
	this.setHTMLDiv(d$("woas_title"), this.create_breadcrumb(new_title));
	document.title = new_title;
};

// function which hooks all messages shown by WoaS
// can be fed with multiple messages to show consecutively
woas.alert = function() {
	for(var i=0,l=arguments.length;i < l;++i) {
		alert("WoaS: "+arguments[i]);
	}
};

// same as above, but for unhandled errors
woas.crash = function() {
	for(var i=0,l=arguments.length;i < l;++i) {
		alert("WoaS Unhandled error\n----\n"+arguments[i]);
	}
};

// PVHL: have simplified usage (here just to document):
//   set by 'Lock::' in 'set_current' is set, cleared by load_as_current.
woas.currently_locking = '';
// initialize page on loading; called from Special::Lock page
function _lock_page() {
	// do not call if not in a page locking context
	if (woas.currently_locking) {
		d$("btn_lock").value = woas.i18n.LOCK_PAGE.sprintf(woas.currently_locking);
		d$("pw1").focus();
	}
}

function _woas_new_plugin() {
	var title = woas._prompt_title("Please enter plugin name", "Myplugin", true);
	if (title === null)
		return;
	var def_text;
	// provide special include page support
	// --UNSUPPORTED FEATURE--
	if (title.charAt(0) === '@') {
		def_text = "plugins/"+title.substr(1)+".js\n";
	} else {
		def_text = "/* "+title+" plugin */\n";
	}
	woas._create_page_direct("WoaS::Plugins", title, false, def_text);
	// now we will be editing the plugin code
}

// PVHL: make this part of closure for method below
woas._last_filename = null;

// works - one way or another - for all browsers
// retrieve complete path & filename from file input control
// 	 id is optional, default is 'filename_'
//   use_last is optional (used with id)
//   filename is returned if it exists, otherwise empty string
woas.get_input_file_url = function(id, use_last) {
	id = id || 'filename_';
	var f = d$(id), fn = f.value, is_path = /[\\\/]+/;
	if (!fn) {
		this.alert(this.i18n.FILE_SELECT_ERR);
	} else {
		if (!is_path.test(fn)) {
			// read of control failed to provide directory path
			// try known firefox method (early firefox succeeded, so not here)
			if (this.browser.firefox) {
				try {
					netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
					fn = f.value;
				} catch (e) {
					woas.log("NOTICE: exception while attempting to access file path:\n\n" + e);	// log:1
					// PVHL: replace with i18n string!
					alert('Unable to access local files due to browser security settings. ' +
						'To overcome this, follow these steps:\n' +
						'(1) Enter "about:config" in the URL field;\n' +
						'(2) Right click and select New->Boolean;\n' +
						'(3) Enter "signed.applets.codebase_principal_support" ' +
						'(without the quotes) as a new preference name;\n' +
						'(4) Click OK and try loading the file again.');
					fn = '';
				}
			}
			if (!is_path.test(fn)) {
				// couldn't get path; ask for direct entry unless use_last specified
				if (use_last) {
					fn = this._last_filename;
				} else {
					fn = prompt(this.i18n.ALT_BROWSER_INPUT
							.sprintf(this.basename(fn)), this.ROOT_DIRECTORY);
				}
			}
			if (!is_path.test(fn)) {
				fn = false; // why not '' ?
			} else {
				this._last_filename = fn;
			}
		}
	}
	return fn;
}

/*
woas.css.ff2 (string:valid CSS): css added if browser == ff2 when !raw 
woas.css.set(css, raw)
  css (string:valid CSS): the raw css to be set; replaces old css
  raw (boolean, optional): if true browser fixes will not be applied to css
woas.css.get(): returns currently set CSS (string:valid CSS)
*/
woas.css = {
	// PVHL: these probably aren't needed anymore - check.
	FF2: "\npre { white-space: -moz-pre-wrap !important; }\n",
	IE: "\npre { word-wrap: break-word !important; }\n",
	OPERA: "\npre { white-space: -o-pre-wrap !important; }\n",
	
	// TODO: replace with factory function for just this browser
	set: function(css, raw) {
		raw = raw || false;
		// add some browser-specific wrapping fixes
		if (!raw) {
			if (woas.browser.firefox2)
				// fixes are added first so they can be overridden
				// (although they have an !important property attribute)
				css = this.FF2 + css;
			else if (woas.browser.trident)
				css = this.IE + css;
			else if (woas.browser.presto)
				css = this.OPERA + css;
		}
		if (woas.browser.ie)
			woas.dom._cache.stylesheet.cssText = css;
		else {
		// Setting innerText was causing a 13 second delay in Chrome!
		// Current versions of Chrome/Safari (AppleWebKit Windows) seem to be OK with innerHTML
			/*if (woas.browser.chrome || woas.browser.safari)
				woas.dom._cache.stylesheet.innerText = css;
			else*/
			woas.dom._cache.stylesheet.innerHTML = css;
		}
	},
	
	// Not used/needed in public API; can't easily fix this with current code.
	// Can't see this being a problem though.
	get: function() {
		if (woas.browser.ie)
			return woas.dom._cache.stylesheet.cssText;
		// on Chrome/Safari innerHTML contains br tags
		// PVHL: Above is no longer true (see css.set) - was this an early WebKit issue?
		/*if (woas.browser.chrome || woas.browser.safari)
			return woas.dom._cache.stylesheet.innerText;*/
		return woas.dom._cache.stylesheet.innerHTML;
	}
};

/*
woas.ui.display() closure
	pfx:(private) defines the prefix that will be added to all CSS classes
	state: (private) used to track current control state
	dsp is either:
	  (1) object passed to display to set new state;
	       - any dsp key that tests true is set in state
		   - any dsp key that tests false is reset in state if it exists
	  (2) a string that will be tested to see if such a key is set.
	      Possibilities are:
	         view, edit, pswd, wait, locked, unlocked, ro, fix_h, fix_m,
	         no_img, no_back, no_fwd, no_home, no_tools, no_edit, no_lock,
			 no_log, no_debug, no_mts
	      Plug-ins can add anything desired; everything controlled through CSS.
*/
woas.ui.display = (function() {
	var pfx = 'woas_',
		state = {};
	return function(dsp, resize) {
		var clas, s = [];
		// show if state exists for disabling functions
		if (typeof dsp === 'string') {
			return !!state[dsp];
		} else {
			for (clas in dsp) {
				if (dsp.hasOwnProperty(clas)) {
					if (dsp[clas]) {
						state[clas] = true;
					} else if (state[clas] && state.hasOwnProperty(clas)) {
						state[clas] = false;
					}
				}
			}
			for (clas in state) {
				if (state[clas] && state.hasOwnProperty(clas)) {
					s.push(pfx + clas);
				}
			}
			document.documentElement.className = s.join(' ');
		}
		if (resize) { this._resize(); }
	}
}())

/*** src/editor.js ***/
// @module ui.editor
// this sub-module shall contain the whole editor code
woas.ui.editor = {
	_insert_ruler: function() {
		TagThis("\n----\n", "");
	}
};

// class for managing textarea selection - by pr0xy
function TextAreaSelectionHelper(obj) {
	this.target=obj;
	this.target.carretHandler=this; // ?
	this.target.onchange=_textareaSaver;
	this.target.onclick=_textareaSaver;
	this.target.onkeyup=_textareaSaver;
	this.target.onfocus=_textareaSaver;
	if(!document.selection)
		this.target.onSelect=_textareaSaver; // ?
	this.start=-1;
	this.end=-1;
	this.scroll=-1;
	this.iesel=null;
}

TextAreaSelectionHelper.prototype.getSelectedText=function() {
	if (this.iesel)
		return this.iesel.text;
	// Fixes a problem in FF3 where the selection was not being stored in this.start and this.end when selecting multilines
	this.start = d$("woas_editor").selectionStart;
	this.end = d$("woas_editor").selectionEnd;
	return ((this.start>=0)&&(this.end>this.start))? this.target.value.substring(this.start,this.end): "";
};

TextAreaSelectionHelper.prototype.setSelectedText=function(text, secondtag) {
	if(this.iesel) {
		if(typeof(secondtag)=="string") {
			var l=this.iesel.text.length;
			this.iesel.text=text+this.iesel.text+secondtag;
			this.iesel.moveEnd("character", -secondtag.length);
			this.iesel.moveStart("character", -l);
		} else {
			this.iesel.text=text;
		}
		this.iesel.select();
	} else if (this.start>=0 && this.end>=this.start) {
		var left=this.target.value.substring(0,this.start);
		var right=this.target.value.substr(this.end);
		var scont=this.target.value.substring(this.start, this.end);
		if(typeof(secondtag)=="string") {
			this.target.value=left+text+scont+secondtag+right;
			this.end=this.target.selectionEnd=this.start+text.length+scont.length;
			this.start=this.target.selectionStart=this.start+text.length;
		} else {
			this.target.value=left+text+right;
			this.end=this.target.selectionEnd=this.start+text.length;
			this.start=this.target.selectionStart=this.start+text.length;
		}
		this.target.scrollTop=this.scroll;
		this.target.focus();
	} else {
		this.target.value += text + ((typeof(secondtag)=="string")? secondtag: "");
		if(this.scroll>=0) this.target.scrollTop=this.scroll;
	}
};

TextAreaSelectionHelper.prototype.getText=function() {
	return this.target.value;
};

TextAreaSelectionHelper.prototype.setText=function(text) {
	this.target.value=text;
};

function _textareaSaver() {
	if (document.selection) {
		this.carretHandler.iesel = document.selection.createRange().duplicate();
	} else if(typeof(this.selectionStart)!="undefined") {
		this.carretHandler.start=this.selectionStart;
		this.carretHandler.end=this.selectionEnd;
		this.carretHandler.scroll=this.scrollTop;
	} else
		this.carretHandler.start=this.carretHandler.end = -1;
}

function DivTagThis(align) {
	TagThis('<'+'div align="'+align+'">', '<'+'/div>');
}

function TagThis(starttag, endtag){
	woas._editor.setSelectedText(starttag, endtag);
}

function FullTagThis(tag){
	woas._editor.setSelectedText('<'+tag+'>','<'+'/'+tag+'>');
}

function macroTagThis(tagone, tagtwo) {
	tagtwo = typeof tagtwo === 'undefined' ? '' : '("' + tagtwo + '")'
	TagThis('<<<' + tagone + tagtwo + ':\n', '\n>>>');
}

function setUrl(starttag,centertag,endtag) {
	var url=prompt('Link:','http://');
	if (url===null) return;
	var comm=prompt('Link text:','');
	if (comm===null) return;
		woas._editor.setSelectedText(starttag+woas.js_encode(url)+centertag,comm+endtag);
}

function setWikiImage() {
	setImage('[[Include::Image::',']]');
}

function setHTMLImage() {
	setImage('<'+"img src='","' /"+">");
}

function setWikiUrl() {
	setUrl('[[','|',']]');
}

function setWikiIUrl() {
	var url=prompt('Wiki page to link to:','');
	if (url===null) return;
	var comm=prompt('Link text:', url);
	if (comm===null) return;
	if (comm == url)
		woas._editor.setSelectedText('[['+url+']]');
	else
		woas._editor.setSelectedText('[['+url+'|',comm+']]');
}

function setHTMLUrl() {
	setUrl('<'+'a href="','" target="_blank">','<'+'/a>');
}

function setImage(starttag,endtag) {
	var pic=prompt('Image:','');
	if (pic!==null)
		woas._editor.setSelectedText(starttag,woas.js_encode(pic)+endtag);
}

function setTag() {
        var tag=prompt('Set tag:','');
	if (tag!==null)
	woas._editor.setSelectedText("[[Tag::",tag+"]]");
}


/* ]]> */ </script></head>
<body onload="woas._on_load()" onunload="woas._on_unload()" style="cursor: auto;">
<div id="loading_overlay"><noscript>If you are seeing this text, your browser is not javascript-enabled.</noscript><div id="woas_wait_text">Loading Wiki on a Stick...</div></div>
<div id="woas_pwd_mask"><div id="woas_pwd_query">
<h2>Enter a password</h2>
<p><input id="woas_password" size="40" type="password" onkeydown="woas._password_ok(this, event)" /></p>
<p id="woas_password_desc">The password you enter here will be used the next time you attempt to access an encrypted page or lock/unlock a page. It will then be kept or removed depending on the AES key caching option you have chosen in <a class="woas_link" title="WoaS::Help::Special::Options#Do not temporarily cache the AES key" onclick="woas.go_to('WoaS::Help::Special::Options#S59365')">Special::Options</a>.</p>
<p><input value="OK" onclick="woas._password_ok(d$('woas_password'))" class="woas_button" type="button" />&nbsp;<input value="Cancel" onclick="woas._password_cancel()" class="woas_button" type="button" /></p>
</div></div>
<div id="woas_header_wrap"><div id="woas_header"><div class="woas_nav">
<span id="woas_view_mode">
<a id="woas_back" title="Back" onclick="woas.ui.back()"><img src="" /><span>Back</span></a>
<a id="woas_fwd" title="Forward" onclick="woas.ui.forward()"><img src="" /><span>Fwd</span></a>
<a id="woas_home" title="Main Page" onclick="woas.ui.home()"><img src="" /><span>Home</span></a>
<a id="woas_tools" title="Special::Advanced" onclick="woas.ui.advanced()"><img src="" /><span>Tools</span></a>
<a id="woas_unlock" title="Unlock page" onclick="woas.ui.unlock()"><img src="" /><span>Unlock</span></a>
<a id="woas_lock" title="Lock page" onclick="woas.ui.lock()"><img src="" /><span>Lock</span></a>
<a id="woas_key" title="Set password" onclick="set_key()"><img src="" /><span>Key</span></a>
<a id="woas_print" title="Open the Print window" onclick="page_print()" accesskey="p"><img src="" /><span>Print</span></a>
<a id="woas_edit" title="Edit" onclick="woas.ui.edit()" accesskey="e"><img src="" /><span>Edit</span></a>
</span>
<span id="woas_edit_mode">
<a id="woas_cancel" title="Cancel" onclick="woas.ui.cancel()"><img src="" /><span>Cancel</span></a>
<a id="woas_save" title="Save" onclick="woas.save()" accesskey="s"><img src="" /><span>Save</span></a>
</span>
<a id="woas_help" title="Open the Help window" onclick="woas.ui.help()" accesskey="h"><img src="" /><span>Help</span></a>
</div>
<img class="woas_nav" src="" />
<span id="woas_title"></span>
</div></div>
<div id="woas_scroll_wrap"><div id="woas_content" style="padding-top: 65px;">
<div id="woas_menu_wrap"><div id="woas_menu_pad">
<div id="woas_menu" ondblclick="menu_dblclick()"></div>
<a id="woas_menu_edit" title="Edit menu" onclick="woas.ui.edit_menu()"><img src="" /><span>Edit</span></a>
</div></div>
<div id="woas_page_wrap">
<div id="woas_page" ondblclick="page_dblclick()"></div>
<div id="woas_mts"></div></div>
<div id="woas_edit_wrap">
<div id="woas_edit_page_title">Page title: <input id="wiki_page_title" size="50" value="" />&nbsp; <a title="Toggle wiki mark-up buttons" class="woas_editor_link" onclick="d$.toggle('wiki_format_buttons')">Wiki</a>&nbsp;|&nbsp;<a title="Toggle XHTML mark-up buttons" class="woas_editor_link" onclick="d$.toggle('html_format_buttons')">XHTML</a></div>
<div id="wiki_format_buttons">
Wiki Code:
<input class="woas_button_editor woas_u" value="Wiki URL" title="Wiki page link" onclick="setWikiIUrl()" type="button" />
<input class="woas_button_editor woas_u" value="URL" title="External link" onclick="setWikiUrl()" type="button" />
<input class="woas_button_editor" value=" = " title="Level 1 header" onclick="TagThis('= ','')" type="button" />
<input class="woas_button_editor" value="==" title="Level 2 header" onclick="TagThis('== ','')" type="button" />
<input class="woas_button_editor" value="Img" title="Include wiki image" onclick="setWikiImage()" type="button" />
<input class="woas_button_editor woas_b" value="B" title="Bold text" onclick="TagThis('*', '*')" type="button" />
<input class="woas_button_editor woas_i" value="i" title="Italic text" onclick="TagThis('/', '/')" type="button" />
<input class="woas_button_editor woas_u" value="U" title="Underlined text" onclick="TagThis('_', '_')" type="button" />
<input class="woas_button_editor" value="{{{ }}}" title="Nowiki text" onclick="TagThis('{{{\n', '\n}}}')" type="button" />
<input class="woas_button_editor" value="*" title="Bulleted list item" onclick="TagThis('* ','')" type="button" />
<input class="woas_button_editor" value="#" title="Numbered list item" onclick="TagThis('# ','')" type="button" />
<input class="woas_button_editor" value="@" title="Alphanumeric list item" onclick="TagThis('@ ','')" type="button" />
<input class="woas_button_editor" value="Ruler" title="Ruler (horizontal line)" onclick="woas.ui.editor._insert_ruler()" type="button" />
<input class="woas_button_editor" value="Tags" title="Wiki tag or tags" onclick="setTag()" type="button" />
<a class="woas_editor_link" title="Open 'Tables' help page" onclick="woas.ui.tables_help()">Tables</a>
</div>
<div id="html_format_buttons">XHTML Code:
<input class="woas_button_editor woas_b" title="Bold text" value="B" onclick="FullTagThis('strong')" type="submit" />
<input class="woas_button_editor woas_i" title="Italic text" value="i" onclick="FullTagThis('em')" type="submit" />
<input class="woas_button_editor woas_u" title="Underlined text" value="U" onclick="FullTagThis('u')" type="submit" />
<input class="woas_button_editor woas_s" title="Strike-through text" value="S" onclick="FullTagThis('s')" type="submit" />
<input class="woas_button_editor" title="Superscript text" value="Sup" onclick="FullTagThis('sup')" type="submit" />
<input class="woas_button_editor" title="Subscript text" value="Sub" onclick="FullTagThis('sub')" type="submit" />
<input class="woas_button_editor" title="Align selection left" value="Left" onclick="DivTagThis('left')" type="submit" />
<input class="woas_button_editor" title="Align selection center" value="Center" onclick="DivTagThis('center')" type="submit" />
<input class="woas_button_editor" title="Align selection right" value="Right" onclick="DivTagThis('right')" type="submit" />
<input class="woas_button_editor" title="Justify selection" value="Justify" onclick="DivTagThis('justify')" type="submit" />
<input class="woas_button_editor" title="Unordered list" value="List" onclick="FullTagThis('ul')" type="submit" />
<input class="woas_button_editor" title="Ordered list" value="List=" onclick="FullTagThis('ol')" type="submit" />
<input class="woas_button_editor" title="List item" value="li [*]" onclick="FullTagThis('li')" type="submit" />
<input class="woas_button_editor" title="Blockquote (indented text)" value="Blockquote" onclick="FullTagThis('blockquote')" type="submit" />
<input class="woas_button_editor" title="Image link" value="Image" onclick="setHTMLImage()" type="submit" />
<input class="woas_button_editor" title="External link" value="Link" onclick="setHTMLUrl()" type="submit" />
</div>
<div id="woas_editor_container"><div id="woas_editor_sizer"><textarea id="woas_editor" rows="0" cols="0">&nbsp;</textarea></div></div>
</div>
<div id="woas_footer_wrap"><div id="woas_footer"><div id="woas_footer_panel">
<div id="woas_about"><a title="About Wiki on a Stick" onclick="woas.ui.about()">About Wiki on a Stick v0.12.0</a></div>
<a id="woas_debug" title="Toggle debug display" onclick="woas.ui.toggle_debug()">
<img src="" /><span>Debug</span>
</a>
<a id="woas_top" title="Go to top of page" onclick="woas.ui.top()">
<img src="" />
<span>Top</span>
</a>
&nbsp;</div>
<div id="woas_debug_console"><div id="woas_debug_log_container">
<textarea id="woas_debug_log" rows="5" readonly="readonly" cols="0"></textarea></div><input id="woas_debug_log_clear" title="Clear debug log" onclick="d$('woas_debug_log').value=''" value="Clear" class="woas_button" type="button" />
</div></div></div>
</div></div>
<script type="text/javascript">
//<![CDATA[
// this code needs to stay here for some Opera/Safari/Chrome restriction
// on DOM generation from external JavaScript
if (woas.use_java_io) {
	document.write("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>");
}
//]]>
</script>
<div id="woas_custom_accesskeys">&nbsp;</div>
</body></html>
